Fork me on GitHub
#clojure-dev
<
2017-12-10
>
bronsa10:12:42

the reason for the "no matching ctor" error, is because you can't evaluate a function object when the function has closed overs locals

bronsa10:12:18

the reason why (foo) works as opposed to throw as it should, is because it happens that the evaluation of a fn is the fn itself unevaluated. (It gets analyzed as a constantexpr and the eval of constantexpr is the input value itself)

bronsa10:12:14

user=> (defmacro f [] (doto (constantly 1) println))
#'user/f
user=> (f)
#object[clojure.core$constantly$fn__5404 0x5f7b97da clojure.core$constantly$fn__5404@5f7b97da]
#object[clojure.core$constantly$fn__5404 0x5f7b97da "clojure.core$constantly$fn__5404@5f7b97da"]

bronsa10:12:31

as you can see it doesn't get re-evaluated after macroexpansion

bronsa10:12:03

in the case of function invocation however, it doesn't follow simple evaluation anymore

bronsa10:12:19

as the compiler wraps the form in a fn and compiles it, to then invoke the compiled fn

bronsa10:12:43

so ((foo)) becomes instead (fn [] ((foo))).invoke()

bronsa10:12:47

and here's the problem

bronsa10:12:59

because what breaks is actually just (fn [] (foo))

bronsa10:12:09

user=> (fn [] (f))
#object[clojure.core$constantly$fn__5404 0xf478a81 clojure.core$constantly$fn__5404@f478a81]
IllegalArgumentException No matching ctor found for class clojure.core$constantly$fn__5404  clojure.lang.Reflector.invokeConstructor (Reflector.java:163)
user=> 

bronsa10:12:27

because we're now compiling (f) instead of evaluating (f)

bronsa10:12:51

and while evaluation the compiler can act as a no-op when trying to evaluate objects, but when compiling it can't

bronsa10:12:16

and compilation of function instances when the function closes over locals is not possible

bronsa10:12:21

so it fails