-
Notifications
You must be signed in to change notification settings - Fork 49
Rest Args
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.
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 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 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.
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 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.
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)