small medium large xlarge

Photo on 2014-01-09 at 17.03_pragsmall
27 Sep 2014, 18:11
Nathan Irwin Smutz (3 posts)

On page 42-43 fn* (vs fn) is used to ensure the ^:once metadata has effect. (For those listening in (^:once fn* [] … prevents memory leaks by causing Clojure to drop any closed over locals after the function’s first invocation)

Research turns up that fn* is the kind of low-level compiler thing that’s usually mediated by something else; but I’m having trouble finding more than that.

Is there a good source of documentation for the pitfalls and features of fn* ?

E16bc9c356b65d61ee1d74c8f06ae35b_pragsmall
27 Sep 2014, 21:25
Colin Jones (3 posts)

Yep, your research is pretty much the norm, I think. The only uses I’m aware of for fn* are:

  • implementing fn itself (plus some bootstrapping things in clojure.core before fn is created)
  • this :once metadata to avoid memory leaks

If you take a look at the implementation of fn (https://github.com/clojure/clojure/blob/03cd9d159a2c49a21d464102bb6d6061488b4ea2/src/clj/clojure/core.clj#L4293-L4354), you’ll see that it adds a lot: destructuring, pre- and post-conditions, and some error handling bits.

I mostly learned about fn* through reading the Clojure source code, but there’s also a helpful blog post by Christophe Grand with some more detail about the :once bits (seems to be down right now, but: http://clj-me.cgrand.net/2013/09/11/macros-closures-and-unexpected-object-retention/)

Aside from ^:once, there’s no reason I’m aware of for programmers to ever use fn* directly: it’s strictly less useful aside from that.

Hope that helps!

You must be logged in to comment