That applies regardless of how they are spelled, be it [...] or #(...).
(To me, it is a context thing, I think - in lagnuages like C/C#, there parens, brackets, parentheses and even angle brackets flying around, and it is not a problem at all.)
Having maps with `{}` syntax is also nice if you ask me. Makes reading a little bit faster.
What difference does it make when representing code?
I was thinking about it over the day, and realized maybe having special syntax actually is confusing - maybe "normal" lisp with only parens is better. Thanks for the eye-opener.
The idea behind the Lisp reader approach is that custom syntax is used for reading/printing objects of different types, not to demarcate syntactic elements. For example, double quotes are for strings, #P"" will read pathnames, and so on. In Common Lisp, some characters like [ and { are reserved for the user, meaning that no conforming implementation defines a custom syntax based on those characters. And you can define [a b c] to mean (vector a b c), which will build a vector, when executed, to hold the current values of a, b and c. The existing #(a b c) vector syntax is a literal vector that contains symbols.
From this point of view, for Clojure, I don't think it is a bad idea to have a short syntax for vectors, set and map literals. But then, those objects are used when representing code, not because it has a real added value but because the visible syntax is a little bit nicer (maybe, maybe not). That IMO complexifies tools that work with code and does not really fulfill a practical purpose. If that was for practical reasons, I think bindings would had been better defined as maps: as far as I know, they seem to fit more naturally than vectors for this task. For example:
(let {a 20 b 10} ...)
Somehow when compiling or interpreting the code, you could do "(get symbol env)" where "env" is the surrounding lexical environment associated with the let, which would be computed partly from a parent lexical environment and {a 20 b 10}. The environment and the map could be of the same type and be easy to combine.
But there is no such consideration, and it is actually a good thing that there is no link between how the code is represented and how it is interpreted (also, there can be different interpretations).Basically, I find Clojure a little bit confused about its use of external data representation for code. I would have preferred a simpler syntax for code and keeping those notations for data, where they are self-describing without additional context.
Vectors also differ from lists in that they are ordered and indexed, so in macros and special forms they tend to be used to represent positional bindings.
(let [a [x y]] ...)
(let [x y] ...)
(fn [x y] ...)
As for parenthesis, you have special cases too: (defn foo ([] (foo 0)) ([n] ...))
And sometimes, people aren't sure about what to use: https://github.com/bbatsov/clojure-style-guide/issues/64I recently had to write a project in Ruby and all this random syntax is driving me mad.
(let ([a 5] [b 6]) (display a+b))
I find this easier to parse mentally, but I can see why one wouldn't do it, especially for cond clauses where you might end up having to actually browse parens to add or remove before or after the ].
I use paredit now, so there is really no need for me to do think about parens much at all, but old habits die hard.