views:

1055

answers:

6

One of the people who took the time to comment on my other question about Clojure/LISP syntax pointed out that I had not written my sample code in the standard LISP way. So he was kind enough to rewrite the code snippet and that's a big help. But it raised another question in my mind. Why would this:

(if (= a something)
  (if (= b otherthing)
    (foo)))

which is standard LISP formatting be preferrable to this form:

(if (= a something)
  (if (= b otherthing)
    (foo)
  )
)

which is the way I would have naively formatted this code because of my C++ development background. I'm wondering if there's any benefit to the latter formatting or it's just an entrenched standard (like a QWERTY keyboard). I'm not trying to be argumentative--it's just difficult for me to understand why the first form would be preferable. The second form helps me to see the code structure more easily.

+1  A: 

When you have 10 parentheses to close, it becomes really clunky.

When I used to program Lisp I left a space between the closing parentheses for opening parentheses on the same line and the rest, to simplify counting, like this:

(if (= a something)
  (if (= b otherthing)
    (foo) ))

I guess these days that is no longer needed, as editors are more helpful.

starblue
I think that's a helpful convention; I'll have to try it out. It can really help with code under frequent editing, as you can see where the linesplit should go.
Aaron
That's horrible advice, really.
Luís Oliveira
What's so horrible about it?
starblue
+21  A: 

The way Lisp code is indented is sort of like the significant whitespace in Python, except that it's of course optional. The basic rule of thumb is that you place items in a list underneath one another vertically if they're not on the same line.

(a (b (c (d e)
         (f g))
      (h i j))
   (k l m n))

Without even looking at the parenthesis, you can see that (d e) and (f g) are parameters for c, (c (d e) (f g)) and (h i j) are parameters for b, and (b (c (d e) (f g)) (h i j)) and (k l m n) are parameters for a.

With your example, it should more correctly be formatted as follows:

(if (= a something)
    (if (= b otherthing)
        (foo)))

    ^   ^
  notice how they line up

Now that the level of indent becomes meaningful, you no longer have to rely on balancing parenthesis to get that information, and since it's more compact to put them on the same line as the closing statement, that's what lispers do. Granted, it's not required that Lisp code be formatted this way, but it's a fairly standard convention that people use and can rely on.

Kyle Cronin
Good point about whitespace and Python. You can regard the parentheses as helpers for your editor to determine indentation, and ignore them otherwise. Incidentally, when you get used to Lisp, you will not "see" them anymore.
Svante
I agree that your way of indenting IF forms is both more conventional and esthetically preferable to the OP's way as far as Lisp as a language family is concerned, but the OP's way is, in fact, (and slightly unfortunately so, in my opinion) the Clojure convention.
Matthias Benkard
Funny thing, I just checked Emacs and it indents like the OP with IF, but with a random name it indents like I did above. Maybe there's something special with IF, but the inconsistency is annoying.
Kyle Cronin
the different indent for IF is because 'foo' is what happens if the condition holds and is as such not a parameter of IF.
Sujoy
FWIW, i've seen Java coding standards that required closing curlies to be placed on the same line, much in the same manner.
Constantin
+22  A: 

The closing parentheses on extra lines don't really help with seeing the structure of the code, because you can get the same information from the level of indentation. However, the second form takes up almost twice as many lines, forcing you to scroll more often when reading code.

And if you need to inspect the nested parentheses more closely, an editor that highlights the matching parenthesis will help you. This will also be easier when the matching parenthesis is not too far away.

If expressions get too long and complicated to be easily read, it may also be a sign that you should extract part of the functionality into a separate function.

Christian Berg
That's a good point. I had not really considered that.
Onorio Catenacci
+1  A: 

The simple answer is that your way isn't the way that Lisp's pretty-printer does things. Having ONE TRUE FORMAT is always a good thing for code, and the pprint macro gives you that format built into the language.

Of course, because the pprint macro exists, it's not strictly necessary for you to follow standard code formatting, because people can just run your code through pprint and get what they're used to. However, since everyone else uses pprint, or manually approximates it, you'll have a hard time reading code if you don't do it the same way, and you don't have an easy macro that will turn their code into your preferred format.

Xanthir
Thank you Xanthir; I was unaware of the pprint macro. I'm just learning Clojure and things like this help a lot.
Onorio Catenacci
A: 

The fundamental point missing from these answers is the very real truth of the alternate definition of LISP: Lots of Infuriating & Silly Parentheses. If you really have an indent and a closing parenthesis at the end of each "code block", you're going to end up wrapping around the screen as soon as you start working on a coding project of any useful complexity.

I'm specifically thinking about the long lists of closures, cons, car and cdr calls used to build and parse code strings in my Dragon Book compiler from school days.

The format that I use is the one suggested above, primarily because this is the format that emacs uses.

Bob Cross
+3  A: 

Instead of

(if (= a something)
  (if (= b otherthing)
    (foo)))

You might want to consider

(when (and (= a something)
           (= b otherthing))
  (foo))
jlf