views:

271

answers:

4

I never really thought about this until I was explaining some clojure code to a coworker who wasn't familiar with clojure. I was explaining let to him when he asked why you use a vector to declare the bindings rather than a list. I didn't really have an answer for him. But the language does restrict you from using lists:

=> (let (x 1) x)
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)

Why exactly is this?

+14  A: 

Mostly readability, I imagine. Whenever bindings are needed in Clojure, a vector is pretty consistently used. A lot of people agree that vectors for bindings make things flow better, and make it easier to discern what the bindings are and what the running code is.

Just for fun:

user=> (defmacro list-let [bindings & body] `(let ~(vec bindings) ~@body))
#'user/list-let
user=> (macroexpand-1 '(list-let (x 0) (println x)))
(clojure.core/let [x 0] (println x))
user=> (list-let (x 0 y 1) (println x y))
0 1
nil
Rayne
I vote for this answer, since it beat mine by 2 minutes **AND** has code! Good show!
fogus
True, Hickey mentioned readability reason in his ... concurrency talk, I think it was.
Hamish Grubijan
Using a literal vector also makes it clear it isn't a function call. list-let works but you have to know that first list isn't evaluated normally. Once you have literal vector syntax you might as well take advantage of it.
Alex Stoddard
I tend to write [~@bindings] when needed in my macros instead of ~(vec binding). I found it easier to read.
Nicolas Oury
Hamish: His concurrency talk? When's the last time Rich talked about something that did not involve concurrency? :-)
Ken
+9  A: 

Clojure tries very hard to be consistent. There is no technical reason with a list form could not have been used in let, fn, with-open, etc... In fact, you can create your own my-let easily enough that uses one instead. However, aside from standing out visibly, the vector is used consistently across forms to mean "here are some bindings". You should strive to uphold that ideal in your own code.

fogus
+7  A: 

This is an idiom from Scheme. In many Scheme implementations, square brackets can be used interchangeably with round parentheses in list literals. In those Scheme implementations, square brackets are often used to distinguish parameter lists, argument lists and bindings from S-expressions or data lists.

In Clojure, parentheses and brackets mean different things, but they are used the same way in binding declarations.

Jörg W Mittag
+1  A: 

my guess is that it's a convention

fn used it, defn used it, loop uses.

it seems that it's for everything that resembles a block of code that has some parameters; more specific, the square brackets are for marking those parameters

other forms for blocks of code don't use it, like if or do. they don't have any parameters

Belun