Hi all; here to satisfy the quarterly quota to maintain my status as
"that guy".
This is a questionable proposal. It:
* introduces completely orthogonal, transient concerns (presentation)
into code, ideally a canonical, long-lived source-of-truth
* sets up a bikeshed at the top of every def* form
* adopts idiosyncratic implementation details of a particular editor's
language support (the defrecord example's :indent is particularly obtuse
IMO, even if you are aware of how clojure-mode is implemented)
I *think* I coined the "always two spaces" shorthand for the
(admittedly, minority) position that list forms should be formatted
completely regularly, so as to:
* make formatting a trivial operation, not requiring any "real" reading
* eliminate this entire topic
Here's the first time I talked about this IIRC:
https://groups.google.com/forum/#!msg/clojuredev-users/NzKTeY722-I/3hmNvJulcksJ
Best,
- Chas
On 09/13/2015 06:06 AM, Artur Malabarba wrote:
Hi everyone,
Over at CIDER we're adding a feature where the author of a macro (or
function) can specify how that macro should be indented by adding an
|:indent| metadata to its definition. This way the editor (and other
tools, like cljfmt) will know what's the proper way of indenting any
macro (even those custom-defined) without having to hardcode a
bajillion names.
Here's an example of how you specify the indent spec for your macros
|(defmacro with-out-str "[DOCSTRING]" {:indent 0} [& body] ...cut for
brevity...) (defmacro defrecord "[DOCSTRING]" {:indent [2 nil nil
[1]]} [name fields & opts+specs] ...cut for brevity) (defmacro
with-in-str "[DOCSTRING]" {:indent 1} [s & body] ...cut for brevity...) |
We'd like to hear any opinions on the practicality of this (specially
from authors of other editors).
Below, I'll be saying “macros” all the time, but this applies just the
same to functions.
*Special arguments*
Many macros have a number of “special” arguments, followed by an
arbitrary number of “non-special” arguments (sometimes called the
body). The “non-special” arguments have a small indentation (usually 2
spaces). These special arguments are usually on the same line as the
macro name, but, when necessary, they are placed on a separate line
with additional indentation.
For instance, |defrecord| has two special arguments, and here's how it
might be indented:
|(defrecord TheNameOfTheRecord [a pretty long argument list] SomeType
(assoc [_ x] (.assoc pretty x 10))) |
Here's another way one could do it:
|(defrecord TheNameOfTheRecord [a pretty long argument list] SomeType
(assoc [_ x] (.assoc pretty x 10))) |
/
/
/The point of the indent spec is *not* to specify how many spaces to
use./
The point is just to say “a defrecord has *2* special arguments”, and
then let the editor and the user come to an agreement on how many
spaces they like to use for special and non-special arguments.
*Internal indentation*
The issue goes a bit deeper. Note the last argument in that
|defrecord|. A regular function call would be internally indented as
|(assoc [_ x] (.assoc pretty x 10)) |
But this is not a regular function call, it's a definition. So we want
to specify this form internally has 1 special argument (the arglist
vector), so that it will be indented like this:
|(assoc [_ x] (.assoc pretty x 10)) |
The indent spec we're working on does this as well. It lets you
specify that, for each argument beyond the 2nd, if it is a form, it
should be internally indented as if it had 1 special argument.
*The spec*
An indent spec can be:
* |nil| (or absent), meaning /“indent like a regular function call”/.
* A vector (or list) meaning that this function/macro takes a number
of special arguments, and then all other arguments are non-special.
o The first element of this vector is an integer indicating how
many special arguments this function/macro takes.
o Each following element is an indent spec on its own, and it
applies to the argument on the same position as this element.
So, when that argument is a form, this element specifies how
to indent that form internally (if it's not a form the spec is
irrelevant).
o If the function/macro has more aguments than the vector has
elements, the last element of the vector applies to all
remaining arguments.
* If the whole spec is just an integer |n|, that is shorthand for |[n]|.
*Examples*
So, for instance, if I specify the |defrecord| spec as |[2 nil nil
[1]]|, this is saying:
* |defrecord| has 2 special arguments
* The first two arguments don't get special internal indentation
* All remaining arguments have an internal indent spec of |[1]|
(which means only the arglist is indented specially).
Another example, |reify| is |[1 nil [1]]| (which should be easy to see
now).
|(reify Object (toString [this] (something) else "here")) |
For something more complicated: |letfn| is |[1 [[1]] nil]|. This means
* |letfn| has one special argument (the bindings list).
* The first arg has an indent spec of |[[1]]|, which means all forms
/inside/ the first arg have an indent spec of |[1]|.
* The second argument, and all other arguments, are regular forms.
|(letfn [(twice [x] (* x 2)) (six-times [y] (* (twice y) 3))] (println
"Twice 15 =" (twice 15)) (println "Six times 15 =" (six-times 15))) |
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient
with your first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to clojure+unsubscr...@googlegroups.com
<mailto:clojure+unsubscr...@googlegroups.com>.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.