Arguments: Named, Default Values

140 views
Skip to first unread message

steve....@gmail.com

unread,
May 28, 2008, 10:42:56 PM5/28/08
to Clojure
Rich,

I am really enjoying learning Clojure. Great language! I'm curious:
does Clojure have named arguments or default argument values, as in
Common Lisp? I have not been able to find anything about them on
clojure.org or in a search of this group. If not, would you mind
explaining why you decided not to add them? I know only a little
Common Lisp, but named arguments (with default values) seem like a
very convenient idea for avoiding code duplication when one have many
similar methods or constructor-equivalents. Thanks!

-Steve

Phil Jordan

unread,
May 29, 2008, 6:14:59 AM5/29/08
to clo...@googlegroups.com
I'm not Rich, so I can't talk about the reasoning, but I'll try and give
you some hints about how you can deal with the lack of those features.

steve....@gmail.com wrote:
> I am really enjoying learning Clojure. Great language! I'm curious:
> does Clojure have named arguments or default argument values, as in
> Common Lisp?

You may have noticed that functions in Clojure can be "overloaded" with
varying argument numbers. So you can simulate default argument values
like so:

(defn foo
([bar]
(prn bar))
([]
(foo "foo")))

Here, I'm defining a version of the function with one argument, and one
with no arguments, and the version with no arguments calls the 1-ary
function with a (default) built-in value.

I guess it's not as compact as explicit default arguments, but probably
more powerful.


As for named arguments, you could apply a Ruby-ism and use maps, for
which there is compact reader syntax:

(my-fn arg1 arg2 { :argname arg3 :argname2 arg4 })

Within the function, you could merge that map argument with a map of the
default values, the values set by the user overriding defaults:

(let [default-args { :a 12 :b 25 :c -1 } ]
(defn foo [argmap]
(let [args (merge default-args argmap)]
; use args here: (args :a), (args :b), etc.
)))

(foo { :b 5 }) ; just like calling (foo { :a 12 :b 5 :c -1 })

The aesthetics of that are probably debatable.

~phil

Christophe Grand

unread,
May 29, 2008, 6:47:13 AM5/29/08
to clo...@googlegroups.com
Phil Jordan a écrit :

> steve....@gmail.com wrote:
>
>> I am really enjoying learning Clojure. Great language! I'm curious:
>> does Clojure have named arguments or default argument values, as in
>> Common Lisp?
>>
I think there's no named arguments to stay close to the jvm.

> As for named arguments, you could apply a Ruby-ism and use maps, for
> which there is compact reader syntax:
>
> (my-fn arg1 arg2 { :argname arg3 :argname2 arg4 })
>
> Within the function, you could merge that map argument with a map of the
> default values, the values set by the user overriding defaults:
>
> (let [default-args { :a 12 :b 25 :c -1 } ]
> (defn foo [argmap]
> (let [args (merge default-args argmap)]
> ; use args here: (args :a), (args :b), etc.
> )))
>
> (foo { :b 5 }) ; just like calling (foo { :a 12 :b 5 :c -1 })
>
> The aesthetics of that are probably debatable.
>

You could also use destructuring to ease the pain:

(defn foo [{a :a b :b c :c :or {a 12 b 25 c -1}}]
[a b c])

or better, thanks to Chouser, when symbols match keywords:

(defn foo [{:keys [a b c] :or {a 12 b 25 c -1}}]
[a b c])


(there are also shorthands for strings and symbols: replace :keys by
:strs or :syms)

Christophe

Steve Betten

unread,
May 29, 2008, 7:38:16 AM5/29/08
to clo...@googlegroups.com
Thanks for the suggestions!  It seems like passing a map and using :or provides the functionality I am looking for.  I'm curious what Rich thinks of this idiom, in particular whether he discourages it and why.

-Steve

Rich Hickey

unread,
May 29, 2008, 8:41:00 AM5/29/08
to Clojure
I prefer to take a rest arg (&) of key val key val..., then apply hash-
map to it and destructure in the body, rather than have the caller
pass a map. E.g. see refer or gen-class.

You can also use a macro to make defining such things easier:

http://groups.google.com/group/clojure/msg/51bb53ca077154f8

(note: that macro could probably be done more simply now...)

I had full CL-style argument handling in an early prototype of
Clojure. In short, I consider arity overloading both more flexible and
more efficient than optional arguments, and keyword arguments to be
non-primitive - as shown above, you can implement them with
destructuring and/or macros.

Rich

ozzi

unread,
May 29, 2008, 2:31:43 PM5/29/08
to Clojure
This is a half-baked idea that I never got around to thinking through,
and for that I apologize :-)

For default arguments, how about allowing :or in the argument list? I
envision something like this:

(fn foo [a b c :or {b "bar"}]
[a b c])

(foo 1 2) ; [1 "bar" 2]

Furthermore, how about allowing a map as the argument list?

(fn foo {a :a b :b c :c :or {b "bar"}}
[a b c])

(foo :a 1 :c 2) ; [1 "bar" 2]

Really, it comes down to letting the argument list be any
destructurable form, and adding :or for destructuring lists. Is this
sensible, practical, or desirable? I don't know.
Reply all
Reply to author
Forward
0 new messages