Fork me on GitHub
#clojure
<
2018-02-19
>
eigenhombre00:02:49

Does the new clj tool support the building of uberjars or similar? Or is the idea to always run programs with the clj tool, even in production?

ghadi01:02:29

i've been working on a tool for uberjars, and dominic_m already released one, can't remember the github coords tho

ghadi01:02:31

@eigenhombre you can do java -cp "$(clj -Spath)" .... if you want for production

borkdude09:02:07

@ghadi I haven’t looked into clj much yet (but I think I should). Does that approach support AOT-ing things as well?

borkdude09:02:46

Will clj with the necessary plugins be able to replace lein and boot completely? The thing I like about boot is being able to program your builds. Is the same thing possible with clj?

carocad10:02:35

hey guys, is it possible to extend a Java class with an Interface instead of a protocol? I am trying to make a custom Class have Clojure’s assoc syntax but I cannot find a protocol for it 😞

Markus Åkerlund Larsson10:02:41

An existing class? Not really

val_waeselynck10:02:40

@carocad you would typically use deftype or defrecord for that

carocad11:02:04

@val_waeselynck I think proxy is what I am looking for. Do you know if It can be used even for final classes? I dont see anything in the docs 😕

val_waeselynck11:02:44

I guess not, but why guess when you can try 🙂

val_waeselynck11:02:02

However, why would you want to extend a final class? Final classes are only meant to be instantiated, not extended

carocad11:02:02

well I want to be able to implement Clojure’s assoc, contains and other functions on a class that has already been defined and made final.

carocad11:02:57

So I thought that I had two options: - create a Type and wrap the original instance - create a Proxy and implement the necessary interfaces

val_waeselynck11:02:27

I would go with option 1 - trying to extend a final class sounds like asking for trouble to me

carocad11:02:46

from your comment it seems that it is not possible (dont have a REPL at hand right now). But in any case the option 1 is still on the table so I guess it would work

carocad11:02:21

Yeah, option 1 is probably the safest way to go 😄

carocad11:02:26

thanks for the help

val_waeselynck11:02:21

even though we have protocols in Clojure, most of the time composition is still better than inheritance in my experience

triss11:02:00

ok so I’ve got some massive data structures I keep printing out. Being as we don’t have a nice `.toString()’ in Clojure - what’s the best way to do custom pretty printing of big data structures?

joelsanchez11:02:00

clojure.pprint/pprint

joelsanchez11:02:32

in cljs use console.log and explore the data with the cljs-devtools custom formatter

triss11:02:57

ok datawalk looks like a dream. Thanks @joelsanchez!

qqq11:02:11

I'm surprised there's no (clojure.util/webserver-dom-print ...) yet, where it fires up a ring server, sets up web sockets, loads up a chrome window, and prints the data structure in an interactive gui where you can click +- to expand/close nodes

bronsa16:02:50

there’s clojure.inspector

bronsa16:02:09

which does exactly what you’re asking for, but as a swing app

triss11:02:48

with `pprint’ is there a way to have it print only specific keys from certain maps?

jsa-aerial15:02:48

zprint might be able to do that, not sure. Since it can highlight specific keys and order them in various ways, if it currently cannot do what you want, I'm sure it could and the author is always open to suggestions: https://github.com/kkinnear/zprint

jsa-aerial15:02:59

OK, the :key-ignore-silent option for maps seems to provide what you want - except it goes the other way 'round. You tell it which to 'skip'; not which to keep...

jsa-aerial15:02:46

Yeah, zprint is kind of amazing...

triss11:02:57

I want to ignore a lot of the data in my structure.

qqq11:02:32

might be easiest to run a clojure.walk on the structure to only preserve important info

schmee12:02:22

I’m looking at some disassembled Clojure code and I see this:

invokestatic clojure.lang.Numbers.and(long, long) : long [244]
and when looking at the compiler source code I see this: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Intrinsics.java#L24

schmee12:02:12

shouldn’t that function call have been replaced with an land instruction?

neurogoo15:02:34

I'm writing a small utility app for parsing our local banks bank statement pdf:s and my GF is interested in using that also. So what is best way nowadays to pack Clojure app for use for non-technical people?

delaguardo15:02:34

https://github.com/BrunoBonacci/lein-binplus there is a nice plugin for leiningen that does that

ghadi16:02:54

@schmee IIRC intrinsics only get lowered when present in IfExpr conditions

bronsa16:02:36

depends on the intrinsic

bronsa16:02:02

the other ones anywhere they are applicable

bronsa16:02:10

so curious that you’re seeing that one

bronsa16:02:13

would be interested in a minimal repro

schmee18:02:50

okay, so

(defn foo []
  (bit-and 1 2))
does not get an intrinsic, but if you type hint the function with ^long it does

schmee18:02:57

is this intended behavior?

bronsa18:02:25

because that function otherwise returns a Long

bronsa18:02:32

so the optimization doesn't kick in

schmee18:02:08

hmm… ok. so here’s the actual code I’m doing, all variables are primitive longs:

(loop [i robot]
        (cond
          (or (< i 0) (>= i BOARD-SIZE)) -1
          (not= (bit-and (aget ^longs board i) (dir->byte dir)) 0) i ;; dir->byte is map keyword -> long
          (and (not= i robot) (or (= i blue) (= i green) (= i red) (= i yellow))) (- i step)
          :else (recur (+ i step))))))

schmee18:02:47

so I shouldn’t expect for instance the bit-and here to get optimized?

bronsa18:02:08

give me 20 mins, I'll get to a laptop and look at it

bronsa18:02:14

on my phone atm

schmee18:02:55

ahh, take your time, no hurry at all for me I’m just curious 🙂

schmee16:02:49

cool! shouldn’t be hard to make one since it’s a 20 line fn that basically just compares a bunch of longs

alexstokes18:02:01

im debugging some code and i think i may see a race condition — it would be great if someone could help by confirming my understanding of the semantics of swap! and atoms:

(declare bar) ;; does some stuff
  (defn bar-until [foo]
    (when (pos? @foo)
      (bar)
      (swap! foo dec)))

  (def foo (atom 10))
  (in-a-tight-loop
   (bar-until foo))

alexstokes18:02:24

i am using a counter in an atom to only run some function a limited number of times

alexstokes18:02:21

this function is called in a tight loop and the issue i think i may be seeing is that control passes back into bar-until while there are outstanding updates to foo

alexstokes18:02:57

i realized i don’t understand the exact concurrency semantics of atoms — is the guarantee that foo will be updated before swap! returns? or just that it will be updated some time

alexstokes18:02:36

i essentially want to block until that happens — but it seems like i should avoid something like busy waiting on compare-and-set!

noisesmith18:02:17

@alexstokes atoms are not blocking, they run optimistically and retry if there is contention

noisesmith18:02:39

the problem with that code is that checking for positivity of foo and running the inc are totally uncoordinated actions, and that is your race condition

noisesmith18:02:13

further, you can’t put anything in a swap! that can’t be run multiple times, so you probably don’t want to put the call of bar into the swapping function either (unless it’s idempotent)

noisesmith18:02:29

but you wouldn’t see a problem there until multiple threads are using bar-until

noisesmith18:02:11

@alexstokes there’s no concept of “outstanding updates” to atoms as far as I know - you have individual method bodies calling compare-and-set! repeatedly and eventually committing the result when it succeeds

noisesmith18:02:10

so yes, if you have two threads each updating foo, the first one to attempt a modification will resume before the second one has successfully updated the value

noisesmith18:02:38

if you need locking behavior, you don’t want any of clojure’s built in concurrency objects

noisesmith18:02:03

(but finding a non-locking solution is highly encouraged, and immutable data makes this easier than one might think)

noisesmith18:02:38

you might be able to do what you want in a straightforward manner with agent plus await - agents do lock for each updating function, and they do keep track of pending actions and let you wait on them

noisesmith18:02:55

they are the only built in concurrency container in clojure that doesn’t retry (but with other clojure core libs there’s also core.async channels and maybe some others)

ghadi18:02:02

I think you've confused him @noisesmith. There is a simple fix here: check and swap the atom before running the side effect:

noisesmith18:02:38

oh? - perhaps I’m the one confused

ghadi18:02:48

(defn bar-until [foo]
    (when (< (swap! foo inc) MAX)
      (bar)))

noisesmith18:02:11

oh, right, checking the return value of swap! makes it much simpler doesn’t it

tanzoniteblack18:02:45

I was sitting here trying to figure out where the bug in doing that was which was causing you to not suggest that, @noisesmith

noisesmith18:02:54

at least I identified the problem, so I’m half way there

ghadi18:02:45

"if you're dereffing an atom more than once in a function, you've probably got a race" - quote me

arrdem19:02:21

fixed one of these last night

noisesmith18:02:35

accessing more than once, and at least one access is a deref

noisesmith18:02:28

two swap! calls is fine for example, if you don’t deref too (and use the return value of the most recent swap!)

noisesmith18:02:38

(if I’m thinking this through clearly)

alexstokes18:02:13

swap! has to block in this case tho correct? as in the update has to occur before it can return a value for the #(< % MAX) evaluation

noisesmith18:02:33

swap! blocks the thread calling it, yes

alexstokes18:02:56

so then why would the original code sample have the race condition?

noisesmith18:02:09

because you check the value with @, then run the operation

noisesmith18:02:18

those two operations are not synchronized, so it’s a race

Nicolas Boskovic19:02:00

https://github.com/web3j/web3j/blob/07abcb50594af5966fbcea881d5e132e4b072af8/utils/src/main/java/org/web3j/utils/Convert.java How can I do the equivalent of Convert.Unit.ETHER? I've been trying for a while but I can't come up with the solution

noisesmith19:02:47

Convert$Unit/ETHER

noisesmith19:02:04

inner classes are fictional, they are just classes with $ in the middle of the name

noisesmith19:02:42

(as far as the vm is concerned that is)

Nicolas Boskovic19:02:47

No such namespace, says the REPL

noisesmith19:02:23

in that case you need to import Convert$Unit, or fully qualify it as org.web3j.utils.Convert$Unit/ETHER

Nicolas Boskovic19:02:24

Referring to Convert$Unit, anyways

noisesmith19:02:48

it’s just a class with $ in the name, so importing Convert doesn’t affect its visibility

jjttjj19:02:16

I have a stream of incoming data, and i want to capture an initial value, look it up in a hashmap, see how many subsequent items to capture/partition along with that value. Is this a time to write my own stateful transducer, or is there a higher level function for dealing with this that I'm missing?

(def lookup {5 3 ;;capture the next 3 values after first 5 is seen
             7 1 ;;capture next value. etc.
             0 5})

(def stream [5 ;;capture the next 3 values (do not look those up)
             9 0 7

             7 ;;capture next 1 value
             1

             0
             4 5 8 9 5 ])

=> ((5 9 0 7)  (7 1) (0 4 5 8 9 5))

noisesmith19:02:56

I don’t think a transducer would be useful here - at least not for a first version - this is pretty simple to do with lazy-seq, drop, take

jjttjj19:02:03

actually, i should have mentioned these will be coming in on a core.async channel. Is it still fine to do it the lazy seq way?

noisesmith19:02:27

oh, if it’s coming off a channel then yeah, use drop / take and a volatile

jjttjj19:02:40

cool thanks!

noisesmith19:02:53

but you might find it helpful to write the lazy-seq version first, it’s simpler I think

noisesmith19:02:20

(and the transducer version will be mostly like it, except using a volatile and having more arities etc.)

jjttjj19:02:39

ok good call

schmee21:02:12

I have a protocol with two different implementations, but I want to reuse the same tests for both. any standard approach for doing this with clojure.test?

noisesmith21:02:21

@schmee if you call is inside a defn, then call the defn inside a test, it works

noisesmith21:02:52

I’ve found it’s helpful to construct a string as the second arg to is, describing the specific args supplied - otherwise failures can be ambiguous

noisesmith21:02:28

that is, describing the args to the function - that way you can distinguish failed calls to the same is from different tests

noisesmith21:02:15

another option is to do all the hard work in a function returning a hash-map, then make all your assertions about the values inside that map - then the only duplicate code is the is calls, and not the code that runs the actual test

schmee22:02:43

the is calls are the main thing I want to avoid duplicating

schmee22:02:52

but as you say I guess I could wrap everything in a huge defn and pass the implementations as an argument to that fn

noisesmith22:02:58

the defn approach is good enough in my experience - typically the right solution with clojure.test is just using normal higher order programming

noisesmith22:02:33

there’s also clojure.test/are if you want to make the assertions on multiple results in one test more concise https://clojuredocs.org/clojure.test/are

arrdem22:02:27

are is an awesome macro.

arrdem22:02:40

lets you make example-based tests super terse.

noisesmith22:02:57

yeah I should definitely be using it more often

dominicm22:02:19

https://clojuredocs.org/clojure.template I discovered this gem a little while ago, in a similar vein 🙂

arrdem22:02:14

I found out about that recently but still haven't found a use for it yet.

arrdem22:02:34

when in doubt format 😛

Henry22:02:30

(defn evalWinVariant
  ""
  [a b c]
  (if (and (not= a 0) (not= b 0) (not= c 0))
    (if (and (= a b) (= b c) )
      true
      false)
    false)
  )
I’m new to clojure and i feel like this function could be written much nicer … more the functional way … any suggestions? How would i return false/true in the first case?

seancorfield22:02:30

The inner if could be replaced by its condition -- (if A true false) is equivalent to A

seancorfield22:02:05

And (if A B false) can be replaced by (and A B)

seancorfield22:02:29

In addition, if you want to test for a and c both being equal to b, you can do (= a b c)

seancorfield22:02:06

@sirhenry91 Can those numbers be negative?

Henry22:02:00

nope they cant

seancorfield22:02:20

(also, on style, we use snake-case rather than headlessCamelCase in Clojure, so it would be eval-win-variant ... and since it returns Boolean and we allow ? in a function name, you could call it win-variant? perhaps)

seancorfield22:02:04

OK, so if they are all non-negative, you could use pos? as a predicate instead of (not= a 0) -- I think that would read better?

seancorfield22:02:22

(and (pos? a) (pos? b) (pos? c)
     (= a b c))
and since the result only needs to be true if they are all equal, you could get away with just testing one of the arguments...

seancorfield22:02:31

(and (pos? a) (= a b c))

arrdem22:02:04

Alternative golf -

(defn eval-win-variant
  ""
  [a b c]
  {:pre [(nat-int? a)
         (nat-int? b)
         (nat-int? c)]}
  (and (= a b c)
       (not= a 0)))

seancorfield22:02:30

So we end up with

(defn win-variant?
  ""
  [a b c]
  (and (pos? a) (= a b c)))

arrdem22:02:42

ooh yeah I missed the pos?

seancorfield23:02:45

And just in case you wanted to be really paranoid and test all three arguments are positive: (every? pos? [a b c]) perhaps?

arrdem23:02:11

I'm probably the odd person out here, but I find that preconditions and postconditions are super useful for debugging because they give you precise errors around where in your dataflow something went wrong.

arrdem23:02:24

You can always turn 'em off

ghadi23:02:36

i'm done with pre/post conditions in favor of instrumentation

ghadi23:02:48

as in spec/instrument

Henry23:02:51

@seancorfield That looks splendid, thank you 🙂

seancorfield23:02:53

And welcome to Clojure @sirhenry91!

seancorfield23:02:34

(you may find the #beginners channel helpful since folks there have opted in to helping Clojure novices in great detail)

Henry23:02:59

😇 will do