Clojure – Multi-Arity and Variadic functions

In F#, you can’t overload a let-bound function, and whilst it’s a hindrance sometimes you can generally work around it easily enough since you can still overload members of a class. All you need to do is to wrap the module and constituent functions into a class and overload the class members instead.

Multi-Arity Functions

This is where multi-arity functions come in in Clojure (an arity is simply the number of arguments that a function can take).

One way to define multi-arity functions is to use the defn macro, for instance:

As you’ve probably noticed, it’s possible for one overload to call another, so you can use this technique to set default argument values as shown above. On its own, that’s not very interesting, and an effect that can be easily replicated in F# using a combination of optional parameters and the built-in defaultArg function with class members, even without resorting to overloading (again, this is sadly only supported with class members and not functions..).

Variadic Functions

What is definitely more interesting is Clojure’s support for variadic functions – functions with infinite arity.

A variadic function has a & symbol in its arguments list, which tells the compiler that the next parameter collects all remaining arguments as a sequence. So, if we rewrite the greet function to take one or more arguments we can end up with a variadic function such as:

As you can see, the arguments “Darryl”, “Deepu” and “Tom” has been packed into the argument rest in the function definition and printed as a list (Clojure’s lists are enclosed in parentheses ( ) just like its function invocations). If you come from a .Net background then this behaviour should be familiar to you, because that is how parameter arrays works in .Net.

So what’s so special about variadic functions in Clojure then?

To quote Sebastian Shaw from the excellent X-Men First Class film:

image

In Clojure, there’s a built-in apply function which allows you to ‘unpack’ a sequence and pass the unpacked values to a function as individual arguments. With this, we can now rewrite the variadic version of greet as follows:

Notice that the arguments “Darryl”, “Deepu” and “Tom” are no longer treated as a list but as individual arguments to the print function, pretty neat. This SO answer also sheds some more light on why variadic functions exist in Clojure with some interesting examples and idiomatic use of this type of functions.

 

Links

MSDN – F# Parameters and Arguments

Clojure – Functional Programming

Clojure Docs – apply

SO – Why are many Clojure functions variadic

Clojure Cheatsheet

Learn X in Y minutes – where X = Clojure