Skip to content
Eric Merritt edited this page Jan 26, 2012 · 1 revision

&rest Arguments to Functions

Rest arguments in a language like Joxa, where arity is basically part of the namespace, take a bit of thought to get your mind around. Basically, Joxa like Lisp has the ability to group all remaining arguments into a list at the discretion of the function implementer. This changes the way those functions are called and perhaps referred to.

Defined Functions

In module defined functions rest arguments work like you would expect. For example:

(defn+ i-am-a-rest-fun (arg1 arg2 &rest arg3)
    {arg1 arg2 arg3})

In this case, any time i-am-a-rest-fun is called, the arguments are collapsed down for the third argument. This happens for any call that has more then three arguments.

In this case of namespaces i-am-a-rest-fun/3 can actually be referred to by any arity that is 3 or greater. For example i-am-a-rest-fun/545 still refers to i-am-a-rest-fun/3 because those extra arguments are simply collapsed to the three. With that in mind you could define i-am-a-rest-fun/2 without a problem. However, you could never define i-am-a-rest-fun/5 because i-am-a-rest-fun/3 overrides anything with arguments three or greater. to give a concrete example, you could define:

(defn+ i-am-a-rest-fun (arg1 arg2)
    {arg1 arg2})

and it would be valid and make sense. However, you could not define

(defn+ i-am-a-rest-fun (arg1 arg2 arg3 arg4)
    {arg1 arg2 arg3 arg4})

Because i-am-a-rest-fun/3 already fills that namespace completely.

Specs

Specs follow similar rules as functions. I could create a defspec that looks as follows.

(defspec i-am-a-rest-fun ((erlang/term) (erlang/term) &rest (erlang/term))
    (erlang/term))

and it would be correct. It actually gets translated to the equivalent.

(defspec i-am-a-rest-fun ((erlang/term) (erlang/term) [(erlang/term)])
    (erlang/term))

Anonymous Functions

Anonymous functions work exactly like defined functions. I could do

(fn (one two &rest three)
   {one two three})

I can then assign that to the variable foo and call foo as:

(foo 1 2 3 4 5 6 7 8 9)

and it would do the correct thing.

Variables that Refer to Functions

For the most part variables that reference rest functions work exactly like you would expect. However, in the case where the 'restful-ness' of a variable can not be defined at compile time, a function is created that does the resolution at run time. This mostly happens when variables are passed as arguments to functions. At the moment the argument boundry can not be crossed, so when those variables are used as functions, they are wrapped in a function that does the runtime resolution and calls the correct function with the correct args. This may affect performance.

Apply

Apply also works exactly as you would expect. Any resolvable rest call has the arguments handled correctly at compile time. Any un-resolvable rest call has a function created to correctly handle the arguments at runtime.

Use

The use clause in module declarations take a bit of thinking. To refer to a function in a use clause use the actual arity. In our function above you would use (use :only i-am-a-rest-fun/3)