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.