I looked at the source of lazy-seq I found this:
Clojure 1.4.0
user=> (source lazy-seq)
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
nil
user=>
I was wondering how fn* differs from fn, but I can't seem to find any reference to fn* in the docs. What am I missing, and how is fn* different?
Disclaimer: I'm a long way from a Clojure compiler expert, so take the following with an appropriate quantity of salt.
fn* is an intrinsic version of fn. Much of Clojure is implemented in Clojure, but some of the low-level functions are implemented in Java; fn* is one such.
fn is implemented in terms of fn*. The source is here:
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L42
fn* is implemented in the compiler:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L47
There are actually two different versions of fn*, referred to in the Java by the symbols FN and FNONCE. The first is a "bare" fn* and the second is fn* with the metadata ^{:once true}, which is the version used by lazy-seq.
^{:once true} is used to let the compiler know that the closure containing the function will only be invoked once, and that it can perform closed-over local clearing. See this mailing list thread for more details.
Related
Here's snippet:
(defmacro produce-constantly-fn []
(constantly :value))
(defmacro produce-fn []
(fn [& args] :value))
(defn test-fn []
((produce-fn)))
;; during evaluation of form below it throws:
;; java.lang.IllegalArgumentException
;; No matching ctor found for class clojure.core$constantly$fn__4614
(defn test-constantly-fn []
((produce-constantly-fn)))
Why last function cannot be compiled? The snippet can be considered as some sort macros abuse, but anyway...
I assume you defined your macro body without quoting and you are curious why it results in such a weird error message. If you really meant to define a macro for calling (constantly :value) then you should use quoting and it will work:
(defmacro produce-constantly-fn []
`(constantly :value))
(defn test-constantly-fn []
((produce-constantly-fn)))
=> #'user/test-constantly-fn
(test-constantly-fn)
=> :value
Now going back to your case without quoting. It looks really interesting and mysterious so I did some digging. These are my findings:
When you define a macro:
(defmacro produce-constantly-fn []
(constantly :value))
it will just create a function named produce-constantly-fn and mark it as a macro (it's still a Clojure function).
When you look into the implementation of constantly you will find (docs and meta omitted):
(defn constantly [x]
(fn [& args] x))
Under the hood it will compile to a closure object which will implement IFn and will have a single constructor parameter to close over x parameter. Something like this in Java code:
public class clojure.core$constantly$fn__4614 {
private final Object x;
public clojure.core$constantly$fn__4614(Object x) {
this.x = x;
}
public Object invoke(...) {
return x;
}
// other invoke arities
}
Now when you have following sexp:
(defn test-constantly-fn []
((produce-constantly-fn)))
I noticed that Clojure reader evals (produce-constantly-fn) which should return just a function object (produced by calling (constantly :value)) but I found in debugger that it produces clojure.core$constantly$fn__4614. symbol instead (notice the . at the end of the symbol - it is a Java interop form for calling a constructor). It looks like a function object/value gets somehow converted to a symbol representing its constructor call. I could find that the function value gets converted into Compiler$InvokeExpr object containing references to the compiled class name which is probably somehow converted into the symbol.
The reader tries to resolve clojure.core$constantly$fn__4614. further. It gets transformed by the reader into a call to clojure.core$constantly$fn__4614clojure.core$constantly$fn__4614 class constructor with no parameter.
As you have seen above the constructor of that class requires exactly one constructor thus the compilation fails (in clojure.lang.Compiler.NewExpr constructor body) with:
java.lang.IllegalArgumentException: No matching ctor found for class clojure.core$constantly$fn__4614
I am not sure why the Clojure reader transforms the function value to a symbol with constructor call interop form and causing such behaviour thus I presented only the direct cause of the error message and not the root cause why your code doesn't work. I guess it might be a bug or it was a conscious design decision. From the macro authors it would be better to fail fast and learn that the return value of a macro is not a valid code data but on the other hand it might be very difficult or impossible to determine if the returned data is a valid code or not. It's worth checking on Clojure mailing list.
I think what is going on is: macros resolve before functions.
So if you call macroexpand-1 on the function you get:
(def test-constantly-fn (clojure.core/fn ([] ((produce-constantly-fn)))))
Thus ((produce-constantly-fn)) is called before function and gives listed error.
In Practical Clojure's chapter on Java interop, the authors note the following about the Java interop "syntactic sugar" (e.g. (.method object arguments) instead of (. object method arguments)):
Since these “syntactic sugar” expansions happen in the same compilation phase as macro-expansion, macros that do complex code-generation may need to avoid them and use the new and . (dot) special forms directly.
I don't understand why "syntactic sugar" expansion happening in the same phase as macro expansion is a problem. Is it because there may be issues with the order of expansions?
Macros concerned with generating interop calls typically should use the desugared special form, but that's not because of when desugaring happens, nor is it a problem. And they don't have to: more times than I care to count, I've seen someone write:
(defmacro call [obj method & args]
`(~(symbol (str "." (name method))) ~obj ~#args))
which is just a total mess, compared to how it would look with the appropriate tool:
(defmacro call [obj method & args]
`(. ~obj ~method ~#args))
I have some Clojure code that is trying to interop through a couple layers of Java code (in this case, java.nio.Path by way of java.nio.file.WatchEvent<?>:
(defn unroll-event
[^WatchEvent event]
{ :kind (.kind event)
:context (.context event)
:path (-> event .context .toAbsolutePath .toString)})
In this code, I have type hinted event, so I would think it should be able to figure out what .context is supposed to return, and as such, be able to figure out what .toAbsolutePath and .toString do. I think in this case, since .context is defined has returning a generic type T, I am wondering if I can type hint the call to .context. I've tried just prepending ^java.nio.file.Path to .context, and ^Path and ^String to .toAbsolutePath and toString, respectively, but I still get the warnings:
Reflection warning, junkcode/core.clj:28 - reference to field toAbsolutePath can't be resolved.
Reflection warning, junkcode/core.clj:28 - reference to field toString can't be resolved.
Is there something I can do in this case? Is it because -> is a macro and there are special rules for type hinting within that?
(-> x .blah ^String .bar) expands to, basically, (^String .bar (.blah x)), which is clearly not where you want the hint. The point is that type-hinting does not have special behavior in any context (eg, macros): it's just metadata applied to the source-code symbols. In your example ->, there is no place that you can put metadata on the input form that will cause it to be where you want in the output form. So you need to write some other form, like (-> ^Path (.context event) .toAbsolutePath str), for example.
Also, Clojure's inferencer doesn't know anything about generic types, so a method-returning-T gets treated as a method-returning-Object, which explains why you need to hint at all in here.
I don't know if this has always been the case, but in Clojure 1.4.0, 1.5.1, and 1.6.0, you can type-hint at any point in -> as long as you use parentheses:
user=> (set! *warn-on-reflection* true)
true
user=> (fn [^java.nio.file.WatchEvent e]
(-> e ^java.nio.file.Path .context .toAbsolutePath))
Reflection warning, /private/var/folders/9_/wdph6m796zzc8trzcbtcmhrn5bjpt0/T/form-init8364673644863044068.clj:1:35 - reference to field toAbsolutePath on java.lang.Object can't be resolved.
#<user$eval1995$fn__1996 user$eval1995$fn__1996#8128f39>
user=> ; but no warning if we do
user=> (fn [^java.nio.file.WatchEvent e]
(-> e ^java.nio.file.Path (.context) .toAbsolutePath))
#<user$eval1999$fn__2000 user$eval1999$fn__2000#4747e32a>
The only difference is the parens around .context.
I have been looking at the source for defmacro which uses "let" in its definition:
(def
^{:doc "Like defn, but the resulting function name is declared as a
macro and will be used as a macro by the compiler when it is
called."
:arglists '([name doc-string? attr-map? [params*] body]
[name doc-string? attr-map? ([params*] body)+ attr-map?])
:added "1.0"}
defmacro (fn [&form &env
name & args]
(let [prefix (loop [p (list name) args args]
However, "let" is defined as a macro itself:
(defmacro let
"binding => binding-form init-expr
Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein."
{:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~#body))
Can someone explain how this works as I can't understand how "defmacro" can be defined in terms of things which need "defmacro" to already be defined. (if that makes sense :)
This is possible because before defining defmacro function in core.clj there is already a definition of let at this location (which gets redefined later). Macros are just normal functions and the var they are bound to has meta data key :macro with value true so that at compile time the compiler can differentiate between a macro (which execute at compile time) with a function, without this meta key there is no way to differentiate between a macro and a function because macro itself is a function that happens to process S-expressions.
recusrive macros work fine and occur in many place in both the clojure language core and in other programs. macros are just functions that return S-Expressions, so they can be recursive just as functions can. In the case of let in your example it's actually caling let* which is a different function (its fine to have * in a functions name), so although recursive macros are fine, this doesn't happen to be an example of them
I was reading Clojure in Action chapter 8 about TDD and experimented with the stubbing macro. It uses the dynamic binding mechanism to stub functions. Alas, in Clojure 1.3 it is not possible to use the binding mechanism for non-dynamic vars, so the stubbing macro doesn't work in most cases, unless you explicitly declare the var which points to a function dynamic. Then I wondered how stubbing is done in Midje and tried to find the source for 'provided', but I couldn't find it. So here it goes:
How is 'provided' implemented in a fact in Midje? Can someone explain this in detail?
Clojure 1.3 provides a with-redefs macro that works even with vars that haven't been declared dynamic:
user=> (def this-is-not-dynamic)
user=> (with-redefs [this-is-not-dynamic 900] this-is-not-dynamic)
900
For backward compatibility, Midje uses its own version, whose guts look like this:
(defn alter-one-root [[variable new-value]]
(if (bound? variable)
(let [old-value (deref variable)]
(alter-var-root variable (fn [current-value] new-value))
[variable old-value])
(do
(.bindRoot variable new-value)
[variable unbound-marker])))