Fork me on GitHub

Finally finished my Clojure book and released: - I know I'm preaching to the converted here, but if you wouldn't mind taking a moment to maybe share the link within your social circles I would be very very grateful. Thank you.


Does anyone know whether clojure works with java 8 default methods? i.e. can I proxy/reify or extend-protocol onto interfaces and have underlying default methods just work?


I watched some core.async lectures. In it they say that channels are first class, and that it is special. What is an example of a programming language in which channels are not first class?


once you're used to it, it's hard to imagine otherwise I guess


@borkdude: As I understand it, channels are not first-class in Erlang. Instead, each Actor has its own "inbox" queue.


@stuartsierra: but that's not CSP right?


@borkdude: Yes, but I think that was one motivation for "channels are first class" as a comparison.


I’m having some trouble understanding some build-vs-run-time issues. I have something like this: (def environment (get (System/getenv “SOME_VAR”))). As a def, I’d expect this value to get “baked in” at build time. But when I build a jar with lein uberjar and run it, it appears that the Clojure var gets the value of the environment variable at run time.


I wondered if it was caused by JIT compilation of the namespace where environment is defined so I tried {:uberjar {:aot :all}} in my project.clj but that made no difference. But maybe that’s not sufficient to force AOT compilation?


def doesn't mean the value is fixed at compile-time.


The value of the def will be computed when the namespace is loaded.


And it will be loaded at startup?


A namespace is loaded by being 'require'd by another namespace, or by being the "main" namespace that is the entry point to your application.


@integralist: Just looking over the TOC - looks like a great book


I see, thank you.


@brian.button: thanks for the clj-uuid recommendation, it looks great. I don’t understand how v5 uuids are useful though. There doesn’t appear to be a way to extract the name/namespace info from a generated v5 uuid?


Proposition: it is not good practice to interact with an object via a protocol and as a data structure (record) in the same context.


Is there a common pattern for reducing repetition when an argument needs to get passed through to multiple functions? Say a db-connection or api-client?


I would think long and hard about introducing a protocol and putting the repeated args into the impl object


have any of you had trouble with clj-http not coercing the response body to JSON, even if you do (http/get url {:as :json}) ? two things that might be causing my trouble are 1) the response type is "Content-Type" "application/json; charset=utf-8" instead of just "application/json", and 2) the top-level thingy in the response is a JSON array rather than a JSON object. would either of those cause the response body to pass through as a plain string?


@alejandro: Component addresses this problem in part, by grouping together arguments which frequently need to be passed together.


I try to structure my code so that each function has one "contextual" argument — sometimes a component, sometimes just a map — which gets passed through.


@stuartsierra: thanks. I’m actually integrating component as we speak and was basically referring to the contextual argument that you mention. sounds like doing that and passing it through is the way to go then


Yes, it's hard to improve on function parameters. simple_smile You can try to get clever with macros or dynamic binding but in my experience those cause much more trouble than just typing the one extra argument everywhere.


cool, thanks for the advice. dynamic binding was the other leading candidate, but I don’t love how it can distance changes from their effects


I’d be happier about extra function parameters if currying was easier/more idiomatic


Is there a good reason for (set? (keys {:a 1 😛 2})) to equal false ?


@stand: because keys returns a list, not a set?


why return a list?


well, technically it’s a seq


In Clojure in general seqs are more useful in more places


but, yeah, I see what you mean…if it’s already a map you can be pretty much guaranteed that keys will be a valid set


Doubt it will ever change


Interesting. The reason I asked is because the java HashMap interface does have a keySet method. It looks like the CLJ-69 was trying to bring that in.


boot.user=> (.keySet {:a 1 :b 2})
#{:b :a}


yep, though surprisingly (set? (.keySet {:a 1})) is still false


hmm…that seems like a bug


(class (.keySet {:a 1})) is clojure.lang.APersistentMap$2


set? checks for IPersistentSet, not the j.u.c set

Alex Miller (Clojure team)21:07:35

the problem is that you want keys to have the same order as vals

Alex Miller (Clojure team)21:07:41

and with a set, that won't work


ahh, that makes sense.


Is my understanding correct that if my source contains (def foo (edn/read-string (slurp “config.edn”))), this is evaluated once at build time, and again at load time, if they are different (for example once during lein uberjar, then again when I start the jar)?


And, since testing seems to confirm that, is there any way—perhaps something like CL’s eval-when—to detect whether a particular evaluation is happening during build time or load time?


@enn depends how you compile the lib


@enn there is really not much difference in clojure between "build" time and "load" time


even if you AOT compile it, it will still be executed during both phases


@enn I would add that if you need to know if you are in "build" or "load" time, that's a signal that you shouldn't use def


@nberger yeah, that’s what I’m realizing


I will find a different way to manage configuration.


At one point someone posted here a nice example of doing your configuration loading in its own configuration component using stuartsierra/component, but I can’t find it now.


And I think there was recently a discussion on whether you should have a component to load the configuration, or if it should be a parameter of the system, so you would read it in main and pass it when creating the component, or pass an ad-hoc map when doing tests, or in the user ns...


I like it being a parameter to the system


(perhaps it was the same post/discussion)