Parentheses instead of brackets in ns declaration.
Originally posted in this issue.
I believe that we should use parentheses instead of brackets inside of namespace declarations. The first word of the inner form is special, and thus it should be a list, keeping consistent with the rest of clojure. An example is below; notice where we use both :as and :refer in the same declaration.
(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require (clojure (string :as string
:refer [capitalize])
(set :as set)
(zip :refer :all)
(xml :refer :all))
(clojure.java (shell :as sh)))
(:import java.util.Date
java.text.SimpleDateFormat
(java.util.concurrent Executors
LinkedBlockingQueue)))
Notably, emacs will automatically indent this properly, which it will not do with a vector. One downside of this approach is that it does not work for namespaces without packages (rare). Another is that it is not compatible with clojurescript.
I have been using this approach for months and have found it agreeable.
I think there's fairly good precedent for using vectors instead of lists for NS directive arguments. This is a tools problem and the formatting behavior should be fixed in clojure-mode (and the equivalent for other editors).
What is the precedent? Do you just mean that it is most common? If so, I don't think that we should be talking about preserving the most common approach just yet. It's early days still, and we should be pushing for correctness first. I don't believe that this is a tools problem.
I like approach with vectors since it clearly helps me to denote where are special forms of ns macro and where are arguments for those special forms. That's why we have [] for arguments declaration. For better readability.
Notably, emacs will automatically indent this properly, which it will not do with a vector.
As far as I can see it is the only argument to use such approach (and it is tooling issue, not language style issue). At the same time I bet you can teach emacs to understand and indent seqs as you want in ns macro in clojure code. Personally I never had any issues with indention in ns macro. It's not so hard to indent things manually.
Most codebases and reasonably experienced folks use square brackets.
I would argue that (string :refer [join] :as string) is more readable than [string :refer [join] :as string] because it is clearly a form in its own right. Otherwise, [:refer :as string [join] string] should also make sense.
It might be possible to teach every editor to special-case this instance, but for what gain? You would be creating technical debt for everyone. I'm hoping that the eventual pylint/rubocop equivalent doesn't need to look for things like this. If we do believe that the first element is special, we should treat it as such ourselves.
Apart from readability (which I would challenge), why do we use square brackets?
By using (string :refer [join] :as string) it looks like you are making a call to a function named string. It seems to me natural, as a general rule, to use vectors for data, and parens for code. In the ns-macro it is the listing of the data that is of interest, not what happens at macro expansion time.
That's interesting. Playing the counterpoint, would we be comfortable with:
(ns examples.ns
[:refer-clojure :exclude [next replace remove]]
[:require [clojure [string :as string
:refer [capitalize]]
[set :as set]]])
I'm wondering if the community opinion is that it is desirable to use parentheses around the :require etc. forms because they shadow functions. Even still, I'm not sure what that would say about the (clojure [string :as string] ...) part of it. clojure isn't a function, so why is it in parentheses?
Should we be doing:
(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require [clojure [string :as string
:refer [capitalize]]
[set :as set]]))
To drive my point further, consider:
(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require (clojure (string :as string
:refer [capitalize])
set)))
We've already special cased out the single designation set instead of [set], which to me suggests that it's useful to think about the innermost form as a form.
Square brackets describe data, [clojure [string :as string :refer [capitalize]] is data.
(:require) mimics function call since we have require function.
There is no point in treating arguments to :require as forms instead of data.
Clojure has additional types of brackets, so lets benefit out of that.
Indention is bad excuse since it's pure tooling question.
I would love to have function-like indention for vectors from time to time (Hiccup is good example).
But again, it has nothing to do with style guide.
It's tooling issue.
We've already special cased out the single designation set instead of [set], which to me suggests that it's useful to think about the innermost form as a form.
Special case for single form is to reduce amount of brackets (Clojure is better lisp, remember?). Thinking about innermost form as a form will increase amount of parenthesis, mix data with forms, and it doesn't sound like Clojure way to me.
I disagree wholeheartedly on most accounts, but I've made my claims so no need to reiterate. That said, would you advocate for a change in style from (clojure [string :as string :refer [capitalize]]) to [clojure [string :as string :refer [capitalize]]] then? What you've suggested is not the current standard.
@ToBeReplaced this issue is not something worth arguing about. Use what the majority of the codebases use. For the ns macro forms, consistency is more important than subjective improvements in readability, especially for beginners who don't have any point of reference.
Continuing this conversation is a time waste. @bbatsov if I were you I'd close this issue.
I actually just cloned few repos from github.com/clojure and I can't find anything like (:require (blabla [bla bla bla])) in ns macro calls. Only simple cases like (:require [bla bla bla bla]). So I don't know what do you mean by saying "current standard".
No offence, but I think that conversation is going nowhere already. Just plain arguing with less and less arguments. So I think I will just stop talking :)
Cheers, Max
On Sat, 2013-08-17 at 08:03 -0700, ToBeReplaced wrote:
I disagree wholeheartedly on most accounts, but I've made my claims so no need to reiterate. That said, would you advocate for a change in style from (clojure [string :as string :refer [capitalize]]) to [clojure [string :as string :refer [capitalize]]] then? What you've suggested is not the current standard.
— Reply to this email directly or view it on GitHub.
@Gonzih: I meant the current recommendation in the style guide. You are right, (:require (clojure [string :as string] set)) is rare in favor of (:require [clojure.string :as string] [clojure.set]). That said, it is found in the wild (ex. in Carmine).
I have heard two arguments as counterpoints:
- Consistency with popularity matters.
- The form is data and so should be enclosed in square brackets.
Now, I disagree with 1) entirely considering the popularity of Clojure -- it seems way too early to take on technical debt here (ex. require every tool, linter, etc. to adjust for "consistency", if it's even possible.). However, that's a fair place to disagree, so if the viewpoint is that we need to be backwards consistent with our style, fine. I seem to always be the idealist here.
As for 2), the argument being presented suggests that a change needs to be made to the style guide. Either:
(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require [clojure [string :as string
:refer [capitalize]]
[set :as set]]))
Or:
(ns examples.ns
(:refer-clojure :exclude [next replace remove])
(:require [clojure.string :as string
:refer [capitalize]]
[clojure.set :as set]]))
The most popular is actually the second option. Doing nothing is incorrect. Both @Gonzih and @michaelklishin have made arguments that recommend a change in the style guide.
Just send pull request, guys please take a look and tell me what do you think.
I think it can be closed now.