Clojure can simulate named parameters, or a mix of positional and named parameters. This is really old news, dating back to Clojure 1.2 if evidence serves, but I always have trouble finding this exact syntax, and it is not fully obvious.
Say you want to accept a certain number of optional parameters with names, and perhaps, defaults. It turns out you can combine rest parameters (the ones that come after a &
) with map destructuring.
In the simple case, you don't care what the possible options are, and you don't have any defaults.
(defn named-parameters | |
[& {:as params}] | |
params) |
The keys and values you pass to this function, say (named-parameters :foo 1 :bar 2)
, are collected together as symbol params
.
If you don't provide an even number of values (that is, the same number of keys and values), you'll get a reasonable exception, such as java.lang.IllegalArgumentException: No value supplied for key: :bar
Easy-peasey ... but you need to extract values from the params
map to use them inside the function, e.g.: (:foo params)
. It would be nicer to have them as symbols, just like with normal positional parameters. This is also easy, by leveraging more of the features of map destructuring:
(defn named-params | |
[& {:keys [foo bar] | |
:or {foo "foo-default" bar "bar-default"}}] | |
{:output-foo foo :output-bar bar}) |
The :keys
identifies the keywords expected in the map; it works backwards from the symbol name, foo
, to the expected keyword, :foo
.
There's also a:syms
(for when the keys are expected to be symbols) and:strs
(for when the keys are expected to be strings).
The :or
identifies default values for each symbol.
The end result is that we can rely on defaults from :or
or provide our own values when invoking the function:
(named-params :bar "override-bar") | |
==> {:output-foo "foo-default", :output-bar "override-bar"} |
And since this is Clojure, you can combine all of these things together quite easily ... some positional parameters, some named, some identified by keywords, others identified by symbols.