Posts

by Matt Revelle 
Filed under

clojure

 

Clojure's RestFn

Earlier today on #clojure, there was a brief discussion on how larger (including infinite!) arity functions are implemented in Clojure. An example similar to what started the discussion:

 
(apply + (range 100)) 

 
The interesting bit happens in RestFn and how the compiler lays out the bytecode.
 
The implementation of + is:
 
(defn + 
  "Returns the sum of nums. (+) returns 0." 
  {:inline (fn [x y] `(. clojure.lang.Numbers (add ~x ~y))) 
   :inline-arities #{2}} 
  ([] 0) 
  ([x] (cast Number x)) 
  ([x y] (. clojure.lang.Numbers (add x y))) 
  ([x y & more] 
  (reduce + (+ x y) more))) 

 
There are four implementations of +, which gets used depends on the number of arguments provided. The + function is a RestFn instance and it's applyTo method is called from apply.

So far we have:

 
(apply f xs) -> f.applyTo(xs). 
 

This then calls: 




 f.doInvoke(xs.first(), (xs = xs.next()).first(), xs.next()) 


 

Which matches the implementation that handles the parameter list [x y & more]. The Clojure compiler, when emitting the bytecode for +, places the implementation defined for [x y & more] under the appropriate doInvoke method and overrides RestFn's default implementation of throwing an exception about an unsupported arity.

Filed under  //   clojure   jvm   programming  

Comments [0]