This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
i remember reading somewhere that anonymous functions end up being stored/cached in such a way that keeps them efficient when used more than once, say as an anonymous comparator. is that right?
I also wondered this recently 🙂
https://github.com/clojure-goes-fast/clj-java-decompiler answered, e.g. Clojure is smart enough make fn
s once, in advance, rather than many, on-the-fly
@U45T93RA6 in which case tho, in a loop?
(do (println (fn [x] x)) (println (fn [x] x))) creates two different objects obviously
you must store function instance returned by fn
somewhere, be it local binding or Var or even java reference type
here's the decompilation of
(defn sample []
(do
(println (fn [x] x))
(println (fn [x] x))))
-> https://gist.github.com/vemv/bcd6bb57861531b1b6b9995744d27776@U45T93RA6 how you decompiled sample function, i can't make it work for some reason
@U45T93RA6 its still created two classes for each function, instantiated and called both of them, no optimization there
public static Object invokeStatic() {
((IFn)const__0.getRawRoot()).invoke(new endpoint$sample$fn__528376());
return ((IFn)const__0.getRawRoot()).invoke(new endpoint$sample$fn__528378());
}
> its still created two classes for each function,
yeah, I don't expect Clojure to try comparing different fn
s searching for equality
> instantiated
object creation and short-lived GC are extremely cheap AFAICT
the classes are created once, statically, that was my point. Perhaps a naive compiler would create the classes in runtime
> i mean how you called clj-java-decompiler exactly
plain usage, wrapped in (with-out-str)
, using 0.2.1
(defn my-identity [x] x)
=> #'playsync.core/my-identity
(with-out-str (decompile (my-identity 5)))
=>
"
// Decompiling class: cjd__init
import clojure.lang.*;
public class cjd__init
or
(with-out-str (decompile (fn [] (my-identity 5))))
=>
"
// Decompiling class: playsync/core$fn__13171
package playsync;
import clojure.lang.*;
public final class core$fn__13171 extends AFunction
thanks @U45T93RA6. just saw this thread. that's what i thought!
anonymous functions do not equal true when compared (of course), however they're reused under the hood
hmm. i'm trying out clj-java-decompiler
but i get the following when i run decompile
Execution error (ClassNotFoundException) at jdk.internal.loader.BuiltinClassLoader/loadClass (BuiltinClassLoader.java:582).
sun.misc.URLClassPath
okay i'll get around to installing jdk8 when i have some downtime 🙂 just reread the conversation between you and vemv and i understand now. separate objects but cheaply created and GC'ed? i'm happy to def functions when used often. i was just curious how it all worked underneath.
(let [fx (fn [x] x)
fy (fn [y] y)]
(println (fx 5))
(println (fx 5))
(println (fy 10))
(println (fy 10))
(while nil
(println (fy 10)))
public static Object invokeStatic() {
final Object fx = new core$fn__14873$fx__14874();
final Object fy = new core$fn__14873$fy__14876();
((IFn)const__0.getRawRoot()).invoke(((IFn)fx).invoke(const__1));
((IFn)const__0.getRawRoot()).invoke(((IFn)fx).invoke(const__1));
((IFn)const__0.getRawRoot()).invoke(((IFn)fy).invoke(const__2));
((IFn)const__0.getRawRoot()).invoke(((IFn)fy).invoke(const__2));
while (true) {
final Boolean true = Boolean.TRUE;
if (true == null) {
break;
}
if (true == Boolean.FALSE) {
break;
}
((IFn)const__0.getRawRoot()).invoke(((IFn)fy).invoke(const__2));
}
return null;
}
@joshkh right, functions is just a jvm object, you can store and invoke it, unless you create many function instances in a loop.
In fact there is no difference between anonymous function and named function.
If i understand it correctly.
(def fn-name (fn [x] x))
equals to
(defn fn-name [x] x)
It does not need to guess - just use macroexpand
🙂
(macroexpand '(defn fn-name [x] x))
=> (def fn-name (clojure.core/fn ([x] x)))
and outside the loops each fn
call seems to create a separate object, as shown in thread above and in another little example
(defn f [x] x)
(defn g [x] x)
(def h f)
[(= f g) (= f identity) (= f h)]
=> #'user/f
#'user/g
#'user/h
[false false true]
it seems that Clojure does not do optimization in this case, cause 1-st order objects may used as a different itemsI'm trying to use the clojure java api (for a ticket on java app, used by java users)
IFn fn = Clojure.var("clojure.core", "fn");
IFn vector = Clojure.var("clojure.core", "vector");
fn.invoke(vector.invoke(), null);
but I get
An exception occured while executing the Java class. Parameter declaration missing
ah got it fn.invoke(null, null, vector.invoke(), null)
the two first null's are probably the meta and optinal name.
@ivana @nxtk anonymous functions in loops was the reason i was asking. thanks for the clarification. 🙂
yup, that's where i ended up. i was just curious from a lazy programmer's perspective.
Now that Clojure 1.10 supports extending protocols via metadata, is there any reason to prefer attaching metadata to generic maps instead of creating new records for sets of keys corresponding to a domain object?
I'm wondering what are the use-cases for extending via metadata? Is it more for one-off uses where you want to glue things together without setting up records?
oh right, metadata can be attached to lists and vectors as well, can't use records for those
hi, so I have this collection. for each element, I map it with a function that produces a vec. I'd like to map every element of the coll then flatten/combine all the vecs together
I tried (transduce (map mapping-fn) concat coll)
at first, but that gave me StackOverflowError for some reason. So now i have (transduce (map mapping-fn) (completing (fn [acc next] (into acc next))) [] coll)
. is there a prettier way?
Sounds like you want cat
?
oh nice, mapcat is what I want. it's a transducer too
@williewillus like this
(into [] (comp (map mapping-fn) cat) coll)
thanks!
Yeah, mapcat
as a transducer will work for this case. cat
is useful if you have a more complex pipeline -- or the cat
ting doesn't come after a map
ping 🙂
(into [] (mapcat mapping-fn) coll)
Has anyone run across an error in core.async where it mysteriously tries to close a boolean?
Exception in thread "async-dispatch-49" java.lang.IllegalArgumentException: No implementation of method: :close! of protocol: #'clojure.core.async.impl.protocols/Channel found for class: java.lang.Boolean
I think something weird is going on, as I’m just opening a pipe between two channels I’ve created myself.
One of the channels has been added to a pub.
This seems to be enough to blow everything up.
Manually piping it with a go-loop works. Interesting, and bizarre…
Good idea 🙂
Stopping the REPL and cleaning the cache solved the problem. Thanks for the reminder 🙂

Okay, this is just crazy. Copying the source code of pipe works, but calling it as a function doesn’t.
Looks like it was just one of those weird bugs that crop up from time to time. Restarting the REPL and cleaning the cache fixed it.