Fork me on GitHub
#clojure
<
2019-12-24
>
littleli11:12:27

I have probably stupid question. What strategy would you recommend in case I need to call and use interfaces from here https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html and interop them from Clojure? Is there a sidekick library or something which would help me adapt Clojure code to be used smoothly with APIs which heavily use lambdas (interfaces above)?

littleli11:12:01

currently I'm playing around with reify above calls when needed, it seems to work but it is quite tedious.

Alex Miller (Clojure team)12:12:57

There are a couple libs

Alex Miller (Clojure team)12:12:52

Longer term, we’ve spent quite a bit of time looking at options for native interop for these, haven’t made any decisions yet

vemv12:12:35

Took a look at ike out of curiosity, was a bit disappointed by its intentional lack of focus on performance I'd recommend to just craft a few "snippets" (practically all IDEs have a snippet system) that draft these reifys

👍 4
littleli13:12:43

Thanks guys, I'll explore ike little bit for inspiration.

littleli13:12:01

I think deftype could be useful too, it allows me to better capture environment. Plus there is nice instantiation with ->MyType that is done here for me. Let's see how that goes.

craftybones18:12:23

Does anyone remember this video where Rich explains a bit of persistent data structures in the video? I can’t remember the context, but I have a vague memory of him whiteboarding it?

andy.fingerhut19:12:12

I do not know if this would also be of interest, but one series of on-line articles that goes into depth on the implementation of Clojure's persistent vectors is here: https://hypirion.com/musings/understanding-persistent-vector-pt-1

andy.fingerhut19:12:27

It has several follow-up parts, each one linking to the next

craftybones08:12:04

@U0CMVHBL2 - thank you so much! This is useful!!!

craftybones18:12:15

This is it~ The Brian Beckman one!

andy.fingerhut19:12:53

In attempting to answer this StackOverflow question, I have underestimated my deep knowledge of Clojure, and found something that I'm not sure what is going on: https://stackoverflow.com/questions/59463747/how-does-clojure-bind-variable-parameters/59465336#59465336 It involves the definition of conj inside of the clojure.core namespace, which has a recur call that is a bit subtle.

andy.fingerhut19:12:19

I am currently guessing that if you have a function defined with parameters like [x & xs] , and then you do (recur foo bar) that on the recursive call, x is bound to the value of foo , and xs becomes bound to the value of bar ? If so, I don't think I have ever seen that outside of the clojure.core namespace before.

andy.fingerhut19:12:28

I thought that perhaps doing a clojure.walk/macroexpand-all call on such a function might expand the [x & xs] parameter vector into something with 2 normal parameters, and no & , but that is not the case.

jumpnbrownweasel20:12:41

I think a recur is no different than any other binding, so x is bound to foo and xs is a sequence that has one element, bar.

jumpnbrownweasel20:12:50

(let [[x & xs] [:foo :bar]] xs)
=> (:bar)

andy.fingerhut20:12:14

Well, if you define a function (defn foo [x & xs] (println "x=" x " xs=" xs)) and call it as (foo 1 2) , x becomes 1 and xs becomes (2) .

andy.fingerhut20:12:24

That is not what happens in the recur call of conj

andy.fingerhut20:12:00

In the recur call of conj , the last parameter to recur is a sequence, and it is not being wrapped inside of another sequence, but simply xs becomes that sequence.

jumpnbrownweasel20:12:17

OK, I don't know why that is.

andy.fingerhut20:12:24

Unless I really need that morning coffee more than usual today 🙂

jumpnbrownweasel20:12:52

The doc examples point out this issue.

; Note that recur can be surprising when using variadic functions.

(defn foo [& args]
  (let [[x & more] args]
    (prn x)
    (if more (recur more) nil)))

(defn bar [& args]
  (let [[x & more] args]
    (prn x)
    (if more (bar more) nil)))

; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...

user=> (foo :a :b :c)
:a
:b
:c
nil

user=> (bar :a :b :c)
:a
(:b :c)
nil

; The difference arises because recur does not gather variadic/rest args
; into a seq.

👍 12
jumpnbrownweasel20:12:03

That's a note that someone added in ClojureDocs.

didibus21:12:00

Official doc also talks about it

didibus21:12:23

The recur expression must match the arity of the recursion point exactly. In particular, if the recursion point was the top of a variadic fn method, there is no gathering of rest args - a single seq (or null) should be passed. recur in other than a tail position is an error.

💯 8
dominicm21:12:09

This is a really cool find. I couldn't find a sufficiently good Emoji to express that, sorry.

4
andy.fingerhut22:12:09

I'm simply amazed that I had not run across this in 10 years of serious hobby time on Clojure.

dominicm22:12:24

I don't write a lot of recursive code I guess.

andy.fingerhut22:12:42

I have written a few, but I don't think ever with variadic args on the recursive function