Fork me on GitHub
Aviv Kotek10:01:02

just curious - what is the reasoning to have both Zulip and Slack channels? why not merge to one?


One reason ZulipChat Clojurians was created was because it has unlimited searchable history, for no $ cost. Slack's history for $0 is limited to the last 10K messages or so.


Which of these, or other, on-line forums people use is up to their own individual decisions. There is no entity commanding everyone to use one or the other.


and why would anyone listen to that entity, if it tried?


I find Zulip significantly nicer, with a way better story for managing (navigating, reading) multiple channels and threads. I actually consume clojurians' slack from Zulip (and come here mostly to write)


Some context/rationale was can be found on Clojureverse: TL;dr because of the limited retention, Slack is less suitable to host one's OSS-project or local meetup group, as channels with less traffic will look abandoned quickly.

Aviv Kotek13:01:32

awesome. so where should I ask my clojure-ish questions? 🙂 one-life-time with so many options...


on Slack there's way more folks, but that has the side-effect that your question may 'disappear' quickly.... The topics on Zulip make a question stand out more, but alas, getting an answer might take some time due to less visitors.


Right now, there are more people participating in discussion on Slack than on ZulipChat for Clojure, so you are probably more likely to get answers sooner on Slack. The discussions of most Slack channels is recorded on ZulipChat, where they can be searched over a longer history

Aviv Kotek13:01:36

awesome, thanks!


Because some people prefer Zulip and some people prefer Slack


it's also why we have multiple linux distributions or cars of different colors :man-shrugging:

Eamonn Sullivan11:01:07

Hi, as anyone used the clj-http client with an API that requires a client SSL cert? The term doesn't seem to be mentioned in the documentation. It would be the equivalent of the --cert option in curl.

Eamonn Sullivan11:01:22

Can you point me at an example use?


Why is a function definition with fn referred to as an anonymous function, when the fn signature does include a name. Is it referred to as anonymous as it can be used without a name or because it is often used without a name? Or is it referred to as anonymous because it is not bound to a namespace scoped var. Is it correct to refer to an fn definition as a lambda function or an inline function (as its called inline as part of an expression/form). Thank you.


Many people use fn without a name. It is nice for easier understanding of stack traces if you do use a name for them, although as you say, those names are not callable from a 'global' context, i.e. at the top level of your code.


I personally used fn for years before realizing that you could give a name.


Historically, I believe the name anonymous function for the similar Common Lisp and Emacs Lisp lambda expressions (which used the symbol lambda instead of Clojure's fn ) was in common practice before Clojure was created. AFAIK, they did not have an option to give a name, the way Clojure fn does.


Emacs Lisp manual reference, where they are called anonymous functions:


Thank you, this is very useful. I will be learning Emacs Lisp properly this year, so useful to contrast with Clojure.


I thought it was a general term used across P-langs as a synonym of lambda expression. The definition being that it's not bound to anything.


Often you can take the return value of such a lambda expression and store it as part of some other data structure, e.g. an element of a list, or a value of a dictionary/map/etc. Not sure if that is what you meant by not bound to anything.


And yes, there is a Wikipedia page for "anonymous function" that lists a bunch of programming languages that have the idea:


It mentions Lisp having the idea in 1958, but I am not certain whether the name "anonymous function" was used at that time yet.


I take it to mean the lambda expression as a value is anonymous.


at the end of the day all expressions are anonymous when taken in isolation


right. I think "anonymous function" has that adjective because there are programming languages where you cannot make a function that is nameless.


but you can still make other values without names.


languages without higher-order functions or closures most likely


C has function pointers, but I think a difference with anonymous functions (besides that they cannot be closures) is that they must all have names.


Very useful discussion, thank you. This gives me a lot more context. So my understanding is that although you can use a name with fn, that name is not available outside of the scope of the function itself. Therefore the expression is anonymous as there is no name for code outside of the function scope to refer to it. Including a name in an fun definition is useful for clarifying stack traces and making recursive functions (functions that call themselves). You can bind the function to a global name using def (or the defn macro) or bind the result to a local name using let. Thanks again, very useful discussion.


You can definitely bind the function to a global name using def / def, or to a local name using let, but in general, as for most languages that have functions as values, you can store functions as values anywhere you can store other values (e.g. in a list, in a vector, in a map, set, etc.)


Looks to me like you gave a good summary there


Another definition of expression is that it's the return value you care about. (fn ,,,) returns a function, without side effects. fn still returns something -- is an expression -- when the function is named.

Eamonn Sullivan14:01:28

Hi, another beginner question: I'm having trouble figuring out some java interop. I have an ssl certificate and I'm trying to read the subject (so that I can parse out the email), but I've only gotten this far and can't figure out what to do with an instance of "java.util.Collections". This assumes (import ' (with-open [cert ( "/etc/pki/experiment.p12")] (let [ks (. KeyStore getInstance "PKCS12") c (. ks load cert (char-array "client"))] (. ks aliases))) How do I see that list of aliases?

Eamonn Sullivan15:01:11

Or perhaps someone knows of a clojure library that does this, so I don't have to work this low-level.

Eamonn Sullivan15:01:26

Ah, found enumeration-seq.


in clojurescript, i'd like to reload an audio element after changing its source...


but i don't know how to idiomatically invoke load


document.getElementById("myAudio").load(); looks like what in cljs?


is this a question about literally translating that to interop syntax, or about how to do that operation in some cljs framework like reagent?


if the former, something like (.load (.getElementById document "myAudio"))


or a translation that looks more direct but does the same thing: (-> document (.getElementById "myAudio") (.load))


I've started using -> a lot, because of its consistency between interop and Clojure usage:

(-> obj .val .val .val)
(-> map :val :val :val)
(-> function fn2 fn3 fn4)


So I actually use it for getting keys in map as well, even if only one, and I never need to use get-in in that case, since -> naturally extends as well


(-> map key)
;; instead of
(:key map)
(-> map :key1 :key2 :key3)
;; instead of
(get-in map [:key1 :key2 :key3])


And it can combine between all three:

(-> (obj-returning-fn) .value (map-returning-fn) :user :name)


I think the reason you (and many others) are tripped up on translating that sort of thing is because it is chained method calls you parse it as a single thing, but if you break it up in to step by step method calls then the answer is pretty clear


var x = document.getElementById("myAudio");

Mario C.23:01:07

If I am getting a GUID byte-array, is there something in Clojure/Java that will turn that into a dashed string? If I call str on the byte array itself I get weird characters.

Mario C.23:01:34

I guess any octal to utf-8 is what I am after


octal isn't a datatype, you can just call the String constructor


user=> (String. (byte-array [104 101 108 108 111]) "UTF-8")
(fixed - leaving out encoding is deprecated)


lazy first cut at what I think you want

user=> (map #(format "%2x" %) (byte-array [104 101 108 108 111]))
("68" "65" "6c" "6c" "6f")


@bfabry oh right, but make that "%02x" because leading zeroes are idiomatic I think


I feel like there's probably a cleverer/neater way to do it than converting it into a seq and joining it all up that way, maybe in a java guid class? but it works


right, you can create an actual UUID, but that is formatted quite differently

Mario C.23:01:07

@noisesmith @bfabry Just what I was looking for! Thank you guys!


here's the neat way if you're "embracing the host"

user=> (import 'java.util.UUID)
user=> (.toString (UUID/nameUUIDFromBytes (byte-array [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16])))


(cmd)user=> (java.util.UUID/randomUUID)
#uuid "146dd4f2-35f0-4f2c-b134-7043d012ed27"
(ins)user=> [(.getMostSignificantBits *1) (.getLeastSignificantBits *1)]
[1472066789972135724 -5677789793651331801]
(ins)user=> (java.util.UUID. (first *1) (last *1))
#uuid "146dd4f2-35f0-4f2c-b134-7043d012ed27"


oh I forgot clojure has a #uuid literal


I've never used name based uuids, but I guess that's what's going on if you get a byte array


actually in hindsight I have nfi what "name based uuid" means haha


also .toString with one arg is just str (except it doesn't crash on nil)