Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top