[comp.lang.lisp] Tradition Lisp code formatting

sboswell@sdcc13.ucsd.edu (....What Is?....) (06/23/91)

I wanted to post this a long time ago but feared starting a flame war.
But my curiosity has finally gotten the better of me.  I must know. :)

How did the traditional style of Lisp code turn out to be so crunched
together?

In languages like C, the trend has been to space everything out so
that blocks are visible (see GNU Emacs "c-mode" to see what I mean,
if you don't.)  I find it much more readable like that.  But in my
Lisp books, it seems, comparatively, smashed together!  Here's an
example, from page 115 of _Lisp: 3rd Edition_ by Patrick Henry
Winston and Berthold Klaus Paul Horn:

(defun count-outlyers (list-of-elements)
  (let ((result 0))
    (dolist (element list-of-elements
		     result)
    (when (or (> elements boiling)
	      (< element freezing))
      (setf result (+ result 1))))))

I would have formatted it this way:

(defun count-outlyers (list-of-elements)
    (let
	(
	    (result 0)
	)
	(dolist
	    (element list-of-elements result)
	    (when
		(or
		    (> element boiling)
		    (< element freezing)
		)
	        (setf result (+ result 1))
	    )
	)
    )
)

Whether to split and indent the (element list-of-elements result) is
usually a matter of whether or not the one-line version makes the
functionality immediately obvious, to me.  But to me, the functionality
of let seems much more obvious; the local variable "result" has been
created, and it's used inside a dolist.  (Incidentally, the only
reason I put the defun's argument list in the same line is so I can
do "grep '(defun' file.lisp" from csh to get a list of all the function
prototypes in the source file.)

So far, I've only found one other person who formats the way I do,
and he hates Lisp nowadays :-( so although it's not a very scientific
conclusion, I'd say there's at least a chance of programmers being
turned off by Lisp because they feel lost in all the parentheses and
cannot immediately divine the structure.  (He would get his Lisp
assignments back from the TA, re-formatted to the traditional way :)

I crossposted to a few seemingly unrelated newsgroups in the hopes
of finding people who were disenchanted with Lisp, to ask if this
was part of the reason.

Please give me your thoughts on this.  No Holy War(TM) intended. :-|

Steve Boswell         | This opinion is distributed in the hopes that it
whatis@ucsd.edu       | will be useful, but WITHOUT ANY WARRANTY...
whatis@gnu.ai.mit.edu |

gaynor@brushfire.rutgers.edu (Silver) (06/23/91)

whatis@gnu.ai.mit.edu writes:
> [Why is Lisp generally written so `tightly', rather than spaced out the way
>  one generally sees C et al?  I generally see Lisp written as it appears on
>  immediately below, and not as I prefer, which follows.
>
> (defun count-outlyers (list-of-elements)
>   (let ((result 0))
>     (dolist (element list-of-elements
> 		     result)
>     (when (or (> elements boiling)
> 	      (< element freezing))
>       (setf result (+ result 1))))))
>
> (defun count-outlyers (list-of-elements)
>     (let
> 	(
> 	    (result 0)
> 	)
> 	(dolist
> 	    (element list-of-elements result)
> 	    (when
> 		(or
> 		    (> element boiling)
> 		    (< element freezing)
> 		)
> 	        (setf result (+ result 1))
> 	    )
> 	)
>     )
> )
> ]

One reason may be the common misconception that whitespace is `cheap' or
`free'.  Too much whitespace can be as detrimental to readability as too
little.  This is especially true in the vertical direction, noting that
characters are generally taller than they are wide (for example, standard glass
terminals are ~24x80).

Note that the blocking structures of the two excerpts of code you provide are
not so different.  From your code samples, you claim preference for the style
on the left; standard lisp formatting is on the right.

    expression                          expression subexpression
        subexpression                              subexpression
        subexpression                              subexpression
        subexpression                              ...
        ...

The indentation format on the right is referred to as hanging indents, ie,
hanging the indentation for an expression off of the indent point for the
previous one, wherever it may be.  This style trades some vertical space for
horizontal, taking advantage of the less-used rightmost screen acreage.

This style is the general case.  But sometimes the right edge of the screen
creeps up a little too quickly, so skip to some small extra indentation on the
next line.  For example, the form on the left might have to be abandoned for
the one on the right, below.  (The right edge is indicated by pipes.)

    ...                     |           ...                     |
    (long-function-name 'bla|h          (long-function-name     |
                        'ble|tch          'blah                 |
                        'ble|chh)         'bletch               |
    ...                     |             'blechh)              |
                                        ...                     |

Also, there are times when the semantic differences of some of the leading
arguments should be emphasized to make them distinct from the remaining ones.
This is typical of special forms which control the flow of evaluation.  This
emphasis is usually shown by indenting them farther, or hanging their indents
and not hanging the indents of the remaining elements.  Hard to explain, easy
to show:

  (let ((variable value)                (let
        ...)                                ((variable value)
    bodyform                                 ...)
    ...)                                  bodyform
                                          ...)

The last item to address is the handling of closing parens across expressions
that span multiple lines.  You claim preference for putting them on their own
line indented at the same level as the matching open paren.  In your preferred
style, you dedicate 10 lines to single closing parens, making it over 2.4 times
as long as the other.  That's a LOT! of whitespace.  I can think of a few
reasons why this would be done.  The first is because it facilitates visual
matching.  But with smarter editors that blink match and move over balanced
expressions, that's no win.  The second is because it easier to move blocks of
code around.  That point I'll concede.

Regards, [Ag]

epstein@sunc2.cs.uiuc.edu (Milt Epstein) (06/23/91)

In <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:

>I wanted to post this a long time ago but feared starting a flame war.
>But my curiosity has finally gotten the better of me.  I must know. :)
>
>How did the traditional style of Lisp code turn out to be so crunched
>together?

Well, I guess I consider myself a LISP programmer (common lisp) --
it's been the language I've used most the last few years, although I
have written some C stuff, and before that PASCAL -- so I'll offer
some comments -- although I don't have any amazing insights.


>In languages like C, the trend has been to space everything out so
>that blocks are visible (see GNU Emacs "c-mode" to see what I mean,
>if you don't.)  I find it much more readable like that.  But in my
>Lisp books, it seems, comparatively, smashed together!  Here's an
>example, from page 115 of _Lisp: 3rd Edition_ by Patrick Henry
>Winston and Berthold Klaus Paul Horn:
>
>(defun count-outlyers (list-of-elements)
>  (let ((result 0))
>    (dolist (element list-of-elements
>		     result)
>    (when (or (> elements boiling)
>	      (< element freezing))
>      (setf result (+ result 1))))))

For what it's worth, I would've done this function this way (assuming
it was common lisp):

(defun count-outlyers (list-of-elements &aux (result 0))
  (dolist (element list-of-elements result)
    (when (or (> elements *boiling*)
	      (< element *freezing*))
      (incf result))))

(BOILING and FREEEZING are global variables, I assume.)


>I would have formatted it this way:
>
>(defun count-outlyers (list-of-elements)
>    (let
>	(
>	    (result 0)
>	)
>	(dolist
>	    (element list-of-elements result)
>	    (when
>		(or
>		    (> element boiling)
>		    (< element freezing)
>		)
>	        (setf result (+ result 1))
>	    )
>	)
>    )
>)

Well, as you might expect, I find your first version (and my version
too, of course) much more readable and comprehendable than this second
one.  This second one seems much too spread out and has wasted space
-- when I say that, I mean space that doesn't necessarily help make
the code more readable.  I tried to think about why this might be so,
and came up with the following.

OK, what's the major difference between a language like LISP and a
language like C.  Well, LISP is functional programming and C is
imperative.  What are the consequences of this?  I think that the
goals of formatting are the same in each case (to make things more
readable), but they are realized differently due to the different
styles of the languages.

For one thing, what constitutes "blocks" of code differs.  In LISP,
the blocks will typically be indicated by separate functions, so they
are inherently distinct (and you'll have white space inbetween them).
In C, you may have distinct blocks within the same function (confusing
-- different use of the same term), so you may need to put white space
in to separate the blocks.

Another thing is that the relationship between one line of code and
the next differs.  In LISP, since everything is function calls, the
next line will probably be the arguments to a function call, so you'd
like to have them relatively close by to see what is going on.  In my
personal style (I'm not sure what other LISPers do), I tend to write
small functions, so they may often be only one function call (like a
let, dolist, cond, if), and it often turns out that everything is done
via nested function calls -- and then it seems like spreading things
out makes it harder to see what is going on.  This is the case in the
sample function you gave (and maybe that is why I don't like your
second version).  So, really, this function is just one line of code.
In C, different lines are usually distinct steps or commands, so they
don't need to be so close together.

I'll add that when I do occasionally write a program in C or PASCAL,
I do use this spread out style more, although I still tend to write
small functions.


>So far, I've only found one other person who formats the way I do,
>and he hates Lisp nowadays :-( so although it's not a very scientific
>conclusion, I'd say there's at least a chance of programmers being
>turned off by Lisp because they feel lost in all the parentheses and
>cannot immediately divine the structure.  (He would get his Lisp
>assignments back from the TA, re-formatted to the traditional way :)

I think any different language takes a little getting used to -- if
you just bear with it a little while and get more experience with it,
things will become easier.  Actually, I've TA'd a class that uses LISP
several times, and I've noticed a fair number of people that come from
a C-like background -- not just in the way they format, but in the way
they write the functions.  I've seen many a function formatted like
your second version above (and although I don't like it, I neither
re-format it nor deduct for it, although I do point out the preferred
style, which doesn't always make a difference :-).


>Please give me your thoughts on this.  No Holy War(TM) intended. :-|

What?!?!  You think you can start comparing C and LISP and not start a
holy war?!?!

:-)

-- 
Milt Epstein
Department of Computer Science
University of Illinois
epstein@cs.uiuc.edu

gateley@rice.edu (John Gateley) (06/24/91)

In article <Jun.23.08.57.04.1991.5234@brushfire.rutgers.edu> gaynor@brushfire.rutgers.edu (Silver) writes:

   [discussing reasons for putting one closing paren per line vs. all
   on one]
   The second is because it easier to move blocks of
   code around.  That point I'll concede.

I won't :^). Again, with smarter editors it is just as easy to move
blocks of code around with the dense representation. In particular,
the commands "move-forward-sexpression", "kill-sexpression" and
"reindent-sexpression" are great.

John
gateley@rice.edu
--
"I've thought the thoughts of little children and the thoughts of men
 I've thought the thoughts of stupid people who have never been
 so much in love as they should be and got confused too easily
 to fall in love again." The Residents and Renaldo and the Loaf

gaynor@brushfire.rutgers.edu (Silver) (06/24/91)

I made the mistake of re-reading my own posting.

The format of some of the included code was slightly messed up because of the
author's use of some strange control character (ascii 9?) to indent the code.
[Frigging tabs are much more trouble than they were ever worth.  That's it.
I'm done with them.  In GNU Emacs, I'm setting indent-tabs-mode nil and adding
a hook to something, perhaps write-file, to warn me of their presence.]

As for editors, any editor of reasonable sophistication will blink matching
parens and compute hanging indents.  Determining when special indentation is
necessary is straightforward, but not run-of-the-mill.  [In GNU Emacs, see Info
on Lisp Indent, specifically, lisp-indent-offset and the lisp-indent-hook
property.]

Regards, [Ag]

datangua@watmath.waterloo.edu (David Tanguay) (06/24/91)

In article <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
>How did the traditional style of Lisp code turn out to be so crunched
>together?
[... example showing a more blocky format than the traditional lisp...]

When I recently wrote my first non-trivial Scheme program I used a very
similar format (amazingly similar, I'm tempted to say). Not only did I find
it much more readable, it was also much easier to move code around with VI. 
-- 
David Tanguay                  datanguay@watmath.waterloo.edu
Thinkage, Ltd.                 dat@Thinkage.On.CA

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/24/91)

In article <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
>How did the traditional style of Lisp code turn out to be so crunched
>together?
[... example showing a more blocky format than the traditional lisp...]

When I started out using Lisp I was using punched cards and a B6700.
I laid my Lisp code out just like my Algol code.
    (if <test>
	<then>
	<else>
    )
The thing that made the difference was that I eventually learned to READ
Lisp as well as to WRITE it.  I discovered that when reading good Lisp code
you ignore most of the parentheses.  It's up to the editor to make sure that
parentheses are balanced, I should just be looking at the words and the
layout.  Why highlight something that a fast reader isn't concerned with?
My Lisp layout conventions aren't _quite_ identical to the conventional
style, but they are a _lot_ closer than they used to be.
-- 
I agree with Jim Giles about many of the deficiencies of present UNIX.

dak@sq.sq.com (David A Keldsen) (06/24/91)

datangua@watmath.waterloo.edu (David Tanguay) writes:

>In article <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
>>How did the traditional style of Lisp code turn out to be so crunched
>>together?
>[... example showing a more blocky format than the traditional lisp...]

>When I recently wrote my first non-trivial Scheme program I used a very
>similar format (amazingly similar, I'm tempted to say). Not only did I find
>it much more readable, it was also much easier to move code around with VI. 

All you have to do to move Lisp code around in vi is to d% 
(or "ad% if you prefer).  Delete to the matching paren suffices...
then judicious use of P or p to paste it, and....voila!

(Who says lisp hackers don't use vi?)

Dak
-- 
David A. 'Dak' Keldsen of SoftQuad, Inc. email: dak@sq.com  phone: 416-963-8337
"You'd better get on with it," she said.  "That's fifty green fires and hot
leads to go, with a side order for blisters and scorpions.  Hold the mercy."
	-- _Sourcery_ by Terry Pratchett

gateley@rice.edu (John Gateley) (06/25/91)

In article <2864C3CE.46E7@ibma0.cs.uiuc.edu> epstein@sunc2.cs.uiuc.edu (Milt Epstein) writes:

   [discussing formatting of Lisp]
   OK, what's the major difference between a language like LISP and a
   language like C.  Well, LISP is functional programming and C is
   imperative.

Auugh Auugh Auuugh! Lisp is NOT a functional programming language!!

A functional language is one without side-effects, and Lisp definitely
has side effects. I think what you meant to say was that the style in
Lisp was to package everything into functions, while C tends to
emphasize fewer (and larger) functions. Isn't terminology wonderful?

j
--
"I've thought the thoughts of little children and the thoughts of men
 I've thought the thoughts of stupid people who have never been
 so much in love as they should be and got confused too easily
 to fall in love again." The Residents and Renaldo and the Loaf

dkozak@mahogany29.cray.com (Darryn Kozak) (06/25/91)

In article <20899@sdcc6.ucsd.edu>, sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
> I wanted to post this a long time ago but feared starting a flame war.
> But my curiosity has finally gotten the better of me.  I must know. :)
> 
> How did the traditional style of Lisp code turn out to be so crunched
> together?
> 
> In languages like C, the trend has been to space everything out so
> that blocks are visible (see GNU Emacs "c-mode" to see what I mean,
> if you don't.)  I find it much more readable like that.  But in my
> Lisp books, it seems, comparatively, smashed together!  Here's an
> example, from page 115 of _Lisp: 3rd Edition_ by Patrick Henry
> Winston and Berthold Klaus Paul Horn:
> 
> (defun count-outlyers (list-of-elements)
>   (let ((result 0))
>     (dolist (element list-of-elements
> 		     result)
>     (when (or (> elements boiling)
> 	      (< element freezing))
>       (setf result (+ result 1))))))
> 
> I would have formatted it this way:
> 
> (defun count-outlyers (list-of-elements)
>     (let
> 	(
> 	    (result 0)
> 	)
> 	(dolist
> 	    (element list-of-elements result)
> 	    (when
> 		(or
> 		    (> element boiling)
> 		    (< element freezing)
> 		)
> 	        (setf result (+ result 1))
> 	    )
> 	)
>     )
> )
> 
> Whether to split and indent the (element list-of-elements result) is
> usually a matter of whether or not the one-line version makes the
> functionality immediately obvious, to me.  But to me, the functionality
> of let seems much more obvious; the local variable "result" has been
> created, and it's used inside a dolist.  (Incidentally, the only
> reason I put the defun's argument list in the same line is so I can
> do "grep '(defun' file.lisp" from csh to get a list of all the function
> prototypes in the source file.)
> 
> So far, I've only found one other person who formats the way I do,
> and he hates Lisp nowadays :-( so although it's not a very scientific
> conclusion, I'd say there's at least a chance of programmers being
> turned off by Lisp because they feel lost in all the parentheses and
> cannot immediately divine the structure.  (He would get his Lisp
> assignments back from the TA, re-formatted to the traditional way :)
> 
> I crossposted to a few seemingly unrelated newsgroups in the hopes
> of finding people who were disenchanted with Lisp, to ask if this
> was part of the reason.
> 
> Please give me your thoughts on this.  No Holy War(TM) intended. :-|
> 
> Steve Boswell         | This opinion is distributed in the hopes that it
> whatis@ucsd.edu       | will be useful, but WITHOUT ANY WARRANTY...
> whatis@gnu.ai.mit.edu |


I prefer the "smashed" look myself, both for Lisp and C. And there's no need for a Holy War, because I'm right (just a joke folks).

	Have a nice day,

	Darryn J Kozak

	Cray Research Park
	655F Lone Oak Drive
	Eagan, MN  55121
	USA

	dkozak@cray.com

	(612) 683-5244

	ISS (Integrated Support System) Project


	

carroll@cs.uiuc.edu (Alan M. Carroll) (06/25/91)

 In article <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
>How did the traditional style of Lisp code turn out to be so crunched
>together?
> [... example showing a more blocky format than the traditional lisp...]

For anyone who likes the blocky style, you might want to check out my
Emacs lisp-mode extension in the Epoch distribution. Unfortunately, it
doesn't work in normal Emacs due to a bug in scan_sexps_forward()
(although I haven't tried it in 18.57).

-- 
Alan M. Carroll          <-- Another casualty of applied metaphysics
Epoch Development Team   
Urbana Il.               "I hate shopping with the reality-impaired" - Susan

snead@MDI.COM (Gregory Snead) (06/26/91)

In article <GATELEY.91Jun24143442@gefion.rice.edu>, gateley@rice.edu (John Gateley) writes:
|> In article <2864C3CE.46E7@ibma0.cs.uiuc.edu> epstein@sunc2.cs.uiuc.edu (Milt Epstein) writes:
|> 
|>    [discussing formatting of Lisp]
|>    OK, what's the major difference between a language like LISP and a
|>    language like C.  Well, LISP is functional programming and C is
|>    imperative.
|> 
|> Auugh Auugh Auuugh! Lisp is NOT a functional programming language!!
|> 
|> A functional language is one without side-effects, and Lisp definitely
|> has side effects. I think what you meant to say was that the style in
|> Lisp was to package everything into functions, while C tends to
|> emphasize fewer (and larger) functions. Isn't terminology wonderful?
|> 


I agree with you technically, but I still program as if LISP was a
functional language. In my opinion this makes my programs more
_correct_, at least in theory :{). I think the idea of LISP being
a functional language comes from its roots in lambda calculus. Perhaps
LISP was truly functional in its original conception.

=================================================================
(defun reply-address ()
   (print "A message for Gregory L. Snead") 
   
   (cond ((null (try-this-first snead@mdi.com))
            (try-this-instead uunet!mdisea!snead) )
         (t (print "Sorry, bub! Talk to your Sys Admin")) )
)
=================================================================
 

jeff@aiai.ed.ac.uk (Jeff Dalton) (06/26/91)

In article <20899@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes:
>In languages like C, the trend has been to space everything out so
>that blocks are visible (see GNU Emacs "c-mode" to see what I mean,
>if you don't.)  I find it much more readable like that.  But in my
>Lisp books, it seems, comparatively, smashed together!

The essential idea behind Lisp code formatting is to make it
unnecessary to pay attention to individual parentheses when
reading code.  The C-like style that places lots of close
parens alone on a line makes the individual parens more
significant.

Moreover, in C individual parens aren't put along on a line.
It's { and } that are treated that way.  That doesn't work so
well in Lisp, perhaps because parens are used so often and { }
is too close visualy to ( and ).  However, some Lisp programmers
mix ( ) and [ ] in their code, eg:

   (let ([var1 expr1]
         [var2 expr2])
     ...)

-- Jeff