Fork me on GitHub

➜  ~ clojure
Clojure 1.11.1
user=> (.getDecoder java.util.Base64)
Execution error (IllegalArgumentException) at user/eval1 (REPL:1).
No matching field found: getDecoder for class java.lang.Class
user=> ^D
➜  ~ java -version
openjdk version "19" 2022-09-20
OpenJDK Runtime Environment Temurin-19+36 (build 19+36)
OpenJDK 64-Bit Server VM Temurin-19+36 (build 19+36, mixed mode, sharing)
Why doesn’t this work?


This works (java.util.Base64/getEncoder). I think the real question is does that code you found work, and if so, how?


Omg, thank you! I don’t know how I got so turned around.


Also, yea. Dunno.


Because babaska has its own interpreter thing

👍 1

Looking at 4clojure exercises. Can someone explain why this solution is equivalent to the nth function?

(fn [a b] ((vec a) b))
I understand that vec constructs a vector. The docs don’t mention anything about using a vector as a function though. Is this a typical thing to do in clojure?


Vectors implement IFn, for invoke() of one argument, which they presume is an index and look up in themselves as if by nth, i.e. vectors are functions of their indices. 

👍 2

Ah… I see. I missed that part. Kind of like using a map as a function with a key as the argument for lookups. I guess that makes sense.


Hah. So it looks like

(fn [a b] (a b))
is an even more concise way to write it. No need to cast the list to a vec.


Oh but lists and seqs cannot be called as a function. So that would only work if a is a vec.


The reason for the difference by the way is that clojure tries to make it harder to accidentally write non-performant code. Vectors support quick lookup by index but sequences do not: seqs and lists must be traversed from the head.

👍 1

Hmm… interesting. Just tried it in a real repl and, yeah, it gives the exception you mentioned. It’s weird that said that (fn [a b] (a b)) passes the tests,


Not sure why the 4clojure implementation accepts that. I think it does not use the Java Clojure implementation (might be using clojurescript or SCI but I haven’t looked into it). The different clojure implementations have some notable and some subtle differences.


That’s good to be aware of. I’m glad I asked. I learned a whole lot from this one topic.

👍 1
Fredrik Andersson21:10:05

how do I add something to the end of a list? I'm trying to write a macro that adds a finally expression in the end

Fredrik Andersson21:10:40

i have tried into, cons, conj and everything ends up in the wrong order

Bob B22:10:17

Because lists are linked lists, it's a bit complicated to add at the end - popular options (to my knowledge) include "reverse, conj, reverse" and concatting the list and a list containing the element to be 'appended'. Having said that, with a macro, a thing that happens sometime is unquote-splicing into a list with the appended thing after that; see as an example with-out-str in clojure.core


Another option is transforming to vector, where conj adds to the end.

Sam Ritchie01:10:05

In macro-land you also have the option of

user> (let [xs '(1 2 3)] `(~@xs 4))
(1 2 3 4)

☝️ 2

That also seems to work fine in a normal function context. (clojurescript too)

(defn append [m x] `(~@m ~x))

(append '(1 2 3) 4)  ;; (1 2 3 4)
(append [1 2 3] 4)   ;; (1 2 3 4)

Sam Ritchie13:10:12

yup that’s true, just gets a little more awkward in larger expressions to unquote everything inside the backticked form


Well I was only really suggesting it as a very simple implementation of append (without multiple traversals of the collection). I don't think you would want to litter your code with a bunch of unquote splicing.


Ya this is always annoying when doing macros. You need to either build things up bottom up, think recursively where you call cons on the way back up. Which basically reverses things, because it puts them on a stack and then pops them into the list. Or you can use the tricks others told you about.