views:

1032

answers:

3

In Common Lisp you can do this:

(defun foo (bar &key baz quux)
  (list bar baz quux))

(foo 1 :quux 3 :baz 2) ; => (1 2 3)

Clojure doesn't have keyword arguments. One alternative is this:

(defn foo [bar {:keys [baz quux]}] 
  (list bar baz quux))

(foo 1 {:quux 3 :baz 2}) ; => (1 2 3)

That's too many nested brackets to have to type and read all the time. It also requires an explicit hash-map to be passed in as an argument rather than a flat list.

What's the most idiomatic Clojure equivalent of keyword arguments that doesn't look someone set off a punctuation bomb?

+20  A: 

A simple way to simulate keyword args in clojure is using hash-map on rest parameters like this:

> (defn kwtest [x & e] (:foo (apply hash-map e)))
#'user/kwtest
> (kwtest 12 :bar "ignored" :foo "returned")
"returned"

Rich Hickey provided a macro in this message from the clojure google group that gives you keyword parameters. The corresponding thread contains information about why keyword parameters are not supported by clojure. Basically to avoid the runtime overhead. Rich explains the method I've shown above in this message

rincewind
+7  A: 

A recent addition to clojure.contrib.def is the defnk macro, which enables definition of functions with keyword arguments (see here).

pmf
+6  A: 

To update this answer for Clojure 1.2 there is now full keyword arg support with defaults provided by the map forms of destructing binding:

user> (defn foo [bar &{ :keys [baz quux] 
                        :or {baz "baz_default" quux "quux_default"}}]
         (list bar baz quux))
#'user/foo

user> (foo 1 :quux 3)
(1 "baz_default" 3)
Alex Stoddard