[comp.lang.lisp] Matching Parens

lynch@aristotle.ils.nwu.edu (Richard Lynch) (09/26/90)

I can read LISP code just fine if "standard" parenthesis rules are used.
BUT, when it comes to debugging code known to be faulty, I really hate to try
and figure out which parenthesis the ones at the end of a line are coding.
And it's not enough to assume that the code is lined up correctly (even by
the editors that supposedly line it up for you.)
That's why I always follow these rules:

A closing parenthesis can only appear:
  A.  In the same line as the open parenthesis.
  B.  In the same column as the open parenthesis.

The indentation for arguments on lines below the function is 2 spaces.  Always.

Thus, my code looks like this:

(defun insert-menu (menu &optional (place nil))
"Inserts menu at place in the menubar.  If place is a menu, the new menu goes
after it.  If place is an integer, the menu goes in that ordinal position."
  (let ((need-update (installed-p)))
    (if place
      (let* ((old-menus (menus))
             (len (length old-menus))
            )
        (when (isa-p place *menu*)
          (let ((pos (position place old-menus)))
            (if pos
              (setq place (1+ pos))
              (setq place (1+ len))
        ) ) )
        (if (integerp place)
          (progn
            (setq place (max 0 place))
            (setq place (min place (1+ len)))
            (if (= place (1+ len))
              (add-menu menu)
              (set-menus (nconc (subseq old-menus 0 place)
                                (list menu)
                                (subseq old-menus  place len)
          ) ) )          )
          (cerror "Adding ~S to end of menubar..."
                  "Invalid place specifier ~S for insert-menu.~%~
                   place must be an integer or menu." place
                  (add-menu menu)
          )
      ) )
      (add-menu menu)
    )
    (if need-update (set-menubar (menus)))
) )

Actually, before you flame me, I am aware that on lines that have just
right parens, they are in reverse order and thus my rules are incorrectly
stated.  But I consider them "isomorphic" in some sense.

I hardly ever have parenthesis problems, and when I do, I find the error very
quickly.
The expense of a lot of lines with just right parens is worth the benifit of
minimal debugging time to me.
Anyone else use this, or am I all alone here?

"TANSTAAFL" Rich lynch@aristotle.ils.nwu.edu

ncramer@bbn.com (Nichael Cramer) (09/27/90)

lynch@aristotle.ils.nwu.edu (Richard Lynch) writes:
>  .... [Suggested indentation rules] ....
>  A.  In the same line as the open parenthesis.
>  B.  In the same column as the open parenthesis.
>  .... [Example deleted] ....

First, a comment: any decent editor (e.g. Zmacs) will negate (certainly
severly lessen) the need for this sort of thing.  *However*, I do realize
that among our brethren and sistern are poor souls caught in the bowels of
*NIX and other such precambrian systems where, through no sin of their own,
such contortions are necessary.

That off my chest, I would only make one suggestion: that you change Rule B
to read:

>  B.  In the same column plus one as the open parenthesis.

For example

  (YU-SHIANG-KITTY
   ARG-1
   ARG-2
   )

Among the reasons for this are:

 o It avoids having a close parentesis in the first column, which can
   potentially screw up the way some editors do things like count number
   of forms in a buffer, etc. (Indeed it is typically A GOOD THING not to
   have anything in the first column except the opening paren of a top 
   level form or a comment.)

 o It "indicate" where a next argument would go --i.e. you wouldn't line
   the args up with opening parentheses.

 o Among code that I've seen, this seems to be more standard than your 
   Rule B.

Cheers
NICHAEL  
nichael@bbn.com  --  Forward Quarter Guard and Captain, BBN Calvin Ball Team.

straz@media-lab.MEDIA.MIT.EDU (Steve Strassmann) (09/27/90)

   From: lynch@aristotle.ils.nwu.edu (Richard Lynch)
   Newsgroups: comp.lang.lisp
   Date: 25 Sep 90 22:15:43 GMT

   I can read LISP code just fine if "standard" parenthesis rules are used.
   BUT, when it comes to debugging code known to be faulty, I really
   hate to try and figure out which parenthesis the ones at the end of
   a line are coding.

   The expense of a lot of lines with just right parens is worth the
   benifit of minimal debugging time to me.  Anyone else use this, or am
   I all alone here?

Nothing personal, but I hope you're all alone.  If people paid half as
much attention to their user interface as they did to their compilers,
we wouldn't have to deal with silliness like this.

Perhaps you should be using an editor like emacs that comes with some
smarts about traditional lisp formatting. For me at least, the
indentation of the immediately following line tells me all I need to
know about any close-parens.

For example, in lisp-mode in many versions of emacs, <tab> indents a
given line, and <C-M-q> indents a given s-expression. Typing a close
parenthesis blinks the corresponding open parenthesis. <C-M-f> and
<C-M-b> take you back and forth over a given s-expression so you can
see its beginning and end.

mikel@Apple.COM (Mikel Evins) (09/27/90)

In article <3474@media-lab.MEDIA.MIT.EDU> straz@media-lab.MEDIA.MIT.EDU (Steve Strassmann) writes:
>
>For example, in lisp-mode in many versions of emacs, <tab> indents a
>given line, and <C-M-q> indents a given s-expression. Typing a close
>parenthesis blinks the corresponding open parenthesis. <C-M-f> and
><C-M-b> take you back and forth over a given s-expression so you can
>see its beginning and end.

For this kind of thing I like the EMACS-oid editor in Macintosh Allegro
Common Lisp even better. Like the usual Lisp-mode EMACS, Fred (the
Emacs in MACL) reindents when you type tab. Placing the text insertion
point next to a parenthesis starts the matching paren blinking, and
it just keeps doing it, so not only do you see where it is, you keep
seeing where it is (you don't forget that way; I don't know about
other people, but my short-term memory fails me with reference to this
kind of detail sometimes). By the way, the blinking is done by alternately
making the paren visible and invisible, rather than by blinking a
block cursor or something, so it's not visually obnoxious. Double-clicking
the mouse button while the pointer is next to a paren selects the entire
expression, displaying it in reverse video. Hitting tab then reindents
the selected text.

Little things like this can make a huge difference in the convenience
of a programming environment.
--me

lynch@aristotle.ils.nwu.edu (Richard Lynch) (09/28/90)

>>I sez:
>>  I like to make closing parens be on the same line or straight below the
>>  opening paren.

>straz@media-lab.MEDIA.MIT.EDU (Steve Strassmann) sez
>Nothing personal, but I hope you're all alone.  If people paid half as
>much attention to their user interface as they did to their compilers,
>we wouldn't have to deal with silliness like this.
>
>Perhaps you should be using an editor like emacs that comes with some
>smarts about traditional lisp formatting. For me at least, the
>indentation of the immediately following line tells me all I need to
>know about any close-parens.
>
>For example, in lisp-mode in many versions of emacs, <tab> indents a
>given line, and <C-M-q> indents a given s-expression. Typing a close
>parenthesis blinks the corresponding open parenthesis. <C-M-f> and
><C-M-b> take you back and forth over a given s-expression so you can
>see its beginning and end.

Just for the record, I *AM* using an EMACS-like editor (FRED:  Fred
Resembles Emacs Deliberately) as described in another follow-up.  It goes
emacs one better by flashing the matching paren on and off AUTOMATICALLY
when the cursor is at a paren.  This means you don't have to ALTER code to
INSPECT it which seems barbaric (though admittedly trivial) to me.  Nor do
you have to memorize arcane keyboard commands to see a whole expression.  A
double click on a closing paren will hightlight the entire form.

<FLAME ON>
As far as interface goes, *I'M* using a Mac where more thought has gone
into the interface than went into the whole compiler of most other systems.
<FLAME OFF>

What precisely is silly about having clear, concise, simple, FOOLPROOF
rules about where a matching paren can be found?  Can you look at a
print-out of your code (that is NOT debugged and MAY contain parenthesis
errors) and immediately tell me where any given form is closed?  I can for
mine.  Of course you have to indent as well, but a lot of times in writing
code that is long, tedious, and too dissimilar to turn into a function or
macro (such as code that draws a lot of slightly different objects in a
program that pays plenty of "attention to [my] user interface"), the forms
that are being lined up may well be several screenfuls away from each
other.

[A *LONG* time ago I was using SPF on an IBM mainframe.  It allowed you to
HIDE as many lines as you wanted (without deleting them, mind you) so that
you could ignore the sections that you "knew" were right, and line up and
concentrate on the rest.  The hidden lines would be replaced by a single
line with the text "XXXXX lines hidden" in its place.  Would love to see
this feature on my FRED editor in MACL.  Anybody write this yet?]

"TANSTAAFL" Rich lynch@aristotle.ils.nwu.edu

mbr@flash.bellcore.com (Mark Rosenstein) (09/28/90)

In article <12676@accuvax.nwu.edu> lynch@aristotle.ils.nwu.edu (Richard Lynch) writes:

   Path: bellcore!bellcore-2!rutgers!mailrus!accuvax.nwu.edu!mmdf
   From: lynch@aristotle.ils.nwu.edu (Richard Lynch)
   Newsgroups: comp.lang.lisp
   Date: 27 Sep 90 18:44:43 GMT
   Sender: mmdf@accuvax.nwu.edu
   Lines: 52

   <FLAME ON>
   As far as interface goes, *I'M* using a Mac where more thought has gone
   into the interface than went into the whole compiler of most other systems.
   <FLAME OFF>
--Total aside ----
Error messages from the Symbolics compiler, and their use of the
error system are quite impressive. For instance I make package errors
often enuf so that when the debugger says, symbol not found. And then
asks to use symbol in so-and-so package, man life is wonderful!
--End total aside--
   What precisely is silly about having clear, concise, simple, FOOLPROOF
   rules about where a matching paren can be found? 
Parens really aren't very interesting. To my mind code has a shape, that
my editor (GNU) supports. "If" looks like
   (if (some-test)
       (yep-its-true)
       (nope-guess-again))
If it doesn't look like that well something's wrong. Defuns look like
   (defun hi-ima-function (some-arg some-other-arg &rest etc)
      (first-form)
      (second-form)
      (when (some-test)
        (do-some-stuff))
      etc)
[I'm not in lisp mode and my defun isn't in the first line, so I'm
really not sure how many spaces m-c-\ would really put in, but I hope
you get the idea].

   Can you look at a
   print-out of your code (that is NOT debugged and MAY contain parenthesis
   errors) and immediately tell me where any given form is closed? 
Sure. It'll be indented wrong. First thing I do when I look at someone
elses code is run formating over it. Otherwise its just characters.
   I can for
   mine.  Of course you have to indent as well, but a lot of times in writing
   code that is long, tedious, and too dissimilar to turn into a function or
   macro (such as code that draws a lot of slightly different objects in a
   program that pays plenty of "attention to [my] user interface"), the forms
   that are being lined up may well be several screenfuls away from each
   other.
I guess this is a stylistic point, but functions over a page make me
queezy. I guess I'm not embarrased to write a function or macro that'll
only be called once. I find that once I free the functionality, along
comes some other piece of code that wants it.
   [A *LONG* time ago I was using SPF on an IBM mainframe.  It allowed you to
   HIDE as many lines as you wanted (without deleting them, mind you) so that
   you could ignore the sections that you "knew" were right, and line up and
   concentrate on the rest.  The hidden lines would be replaced by a single
   line with the text "XXXXX lines hidden" in its place.  Would love to see
   this feature on my FRED editor in MACL.  Anybody write this yet?]
I guess I do all my hidden stuff in lots of little functions. And
(slight sarcastic voice) I don't have all those empty lines with only
parens on 'em), so my code may be more compact?
Maybe it is all style, but first thing I'd do with the code you sent
me is write a little GNU macro to move all them parens up. 

Mark.

edelson@pooh.ils.nwu.edu (Daniel Choy Edelson) (09/29/90)

In article <12558@accuvax.nwu.edu> lynch@aristotle.ils.nwu.edu (Richard Lynch) writes:

>That's why I always follow these rules:
>
>A closing parenthesis can only appear:
>  A.  In the same line as the open parenthesis.
>  B.  In the same column as the open parenthesis.
>

>The expense of a lot of lines with just right parens is worth the benifit of
>minimal debugging time to me.

>"TANSTAAFL" Rich lynch@aristotle.ils.nwu.edu

I've thought about this for a while, and I can't see any benefit to
it.  

It doesn't help you debug, because if there's a parenthesis problem
then you can't count any of the parens being in the correct column
anymore, and you have to go to the same trouble as normal to find
which right paren is missing.

As others have pointed out, I can't see how it helps at coding time,
because the formatters and electric-paren features of emacs-like code
show you which paren you're matching without you needing to space over
to the appropriate column.

Most important, I think that an experienced lisp programmer spends
very little time debugging parenthesis errors, no matter where he or
she puts the right parens and that the time and space spent in
following these rules is time lost not gained.

I think that a novice lisp programmer would be better served in
learning to use formatters and paren balancers than in taking time to
learn rules like these. 


--
---------
Danny Edelson   	Institute for the Learning Sciences
edelson@ils.nwu.edu 	     Northwestern University
(708) 491-3500                 Evanston, IL 60201

jeff@aiai.ed.ac.uk (Jeff Dalton) (10/02/90)

In article <12676@accuvax.nwu.edu> lynch@aristotle.ils.nwu.edu (Richard Lynch) writes:

>>>  I like to make closing parens be on the same line or straight below the
>>>  opening paren.

>>straz@media-lab.MEDIA.MIT.EDU (Steve Strassmann) sez
>>Nothing personal, but I hope you're all alone.  If people paid half as
>>much attention to their user interface as they did to their compilers,
>>we wouldn't have to deal with silliness like this.

>Just for the record, I *AM* using an EMACS-like editor

Clearly, a good editor is (almost) necessary, but not sufficient.
If you think it's important to be able to find close parens when
reading code, you'll want them to stand out.  But if you want to
bwe able to avoid having to pay much attention to parens when
reading code, you'll want them to be less conspicuous.  At least
that's my view of it.

>This means you don't have to ALTER code to INSPECT it

Do I have to alter code in Emacs?  Not the last time I checked...

><FLAME ON>
>As far as interface goes, *I'M* using a Mac where more thought has gone
>into the interface than went into the whole compiler of most other systems.
><FLAME OFF>

Which is not to say that more thought has gone into the *Lisp*
interface (nor is it the case that more thought = better).

>What precisely is silly about having clear, concise, simple, FOOLPROOF
>rules about where a matching paren can be found?  Can you look at a
>print-out of your code (that is NOT debugged and MAY contain parenthesis
>errors) and immediately tell me where any given form is closed? 

Of course not, and neither can you.  If the code contains parenthesis
errors, the form may not be closed at all.  

Perhaps what you mean is that you can see where the close paren
*should* be.  Well, so can I: on the last line of the form.

But maybe you want to know exactly which paren, not just which line.
That may matter to you, because you want close parens for multi-line
forms to stand out.  Since I *don't* want them to stand out (because
it gets in the way when reading), the "exact location" problem doesn't
matter much to me.

Indeed, one of the main points of proper indentation is to make it
unnecessary to *read* parens.  I agree with mbr@breeze.bellcore.com
(Mark Rosenstein), who writes in <MBR.90Sep28095128@ponape.flash.
bellcore.com>:

   Parens really aren't very interesting. To my mind code has a shape,
   that my editor (GNU) supports.

Besides, you're assuming I have to *debug* my code in order to find
paranthesis errors.  It's really a question of editing, rather than
debugging.  If I think some code has wrong parens, I ask my editor
to reindent it; and that shows me what goes with what.

>     Of course you have to indent as well, but a lot of times in writing
>code that is long, tedious, and too dissimilar to turn into a function or
>macro (such as code that draws a lot of slightly different objects in a
>program that pays plenty of "attention to [my] user interface"), the forms
>that are being lined up may well be several screenfuls away from each
>other.

And when you get to then middle of the thrid screen and see

        )

all on a line of its own, it what way are you better off than I am?
I don't see what your point is.

>[A *LONG* time ago I was using SPF on an IBM mainframe.  It allowed you to
>HIDE as many lines as you wanted (without deleting them, mind you) so that
>you could ignore the sections that you "knew" were right, and line up and
>concentrate on the rest.  The hidden lines would be replaced by a single
>line with the text "XXXXX lines hidden" in its place.  Would love to see
>this feature on my FRED editor in MACL.  Anybody write this yet?]

This is a good example of how an editor can help you to write
unreadable code or, at best, code that can be read only with a
similar editor.  

It's also an example of the kind of coding style that arises in
situations in which a procedure call is regarded as expensive and
where people haven't learned to think in terms of small procedures.

-- Jeff

toad@CS.CMU.EDU (Todd Kaufmann) (10/05/90)

   <FLAME ON>
   As far as interface goes, *I'M* using a Mac where more thought has gone
   into the interface than went into the whole compiler of most other systems.
   <FLAME OFF>

Well, I think you lose here, and are wrong.  I used to be as attached to a
lisp-machine-like editor.  Unfortunately, all it did was keep me from
discovering GNU Emacs.  (``Amen, brother!''  ``tell it like it is!'')

   [A *LONG* time ago I was using SPF on an IBM mainframe.  It allowed you to
   HIDE as many lines as you wanted (without deleting them, mind you) so that
   you could ignore the sections that you "knew" were right, and line up and
   concentrate on the rest.  The hidden lines would be replaced by a single
   line with the text "XXXXX lines hidden" in its place.  Would love to see
   this feature on my FRED editor in MACL.  Anybody write this yet?]

I use this feature in GNU Emacs, for CL and Elisp (although it can work on
arbitrary buffers); it's really nice.  Also, it has some idea of levels, so
you can see one line/per page, open to see top-level comments, defuns, etc.

For example, here's what a 200-line file of mine might look like as some point
when I'm hacking on it:

   ;;; -*- Mode: Lisp -*-

   ;;;% Header ...

   ;;;% Object definition ...

   ;;;% Global parameters controlling panner behavior ...
   ;;;% Draw method for a panner ...

   ;;;% special proc for a link: ...

   #| ...
   |#

   (defun draw-link-scaled (link x0 y0 tx ty scale) ...

   ;;;% click action for a panner ...

   ;;;% Create a panner instance in the current window ...

   ;;;% add the command to the menu ...


Although it could just as easily a 100K file, with an arbitrary amount hiding
in the "...".  Just as you can move up & down lists, you can move up and
levels, and expand and contract on levels or arbitrary regions.


Just one more reason...

john@linus.mitre.org (John D. Burger) (10/10/90)

Pardon me while I pick a few nits:

lynch@aristotle.ils.nwu.edu (Richard Lynch) writes:

>That's why I always follow these rules:

 ...

>The indentation for arguments on lines below the function is 2
>spaces.  Always.
>
>Thus, my code looks like this:

 ...

>      (let* ((old-menus (menus))
>             (len (length old-menus))
>            )

 ...

>          (cerror "Adding ~S to end of menubar..."
>                  "Invalid place specifier ~S for insert-menu.~%~
>                   place must be an integer or menu." place
>                  (add-menu menu)
>          )

 ...

>"TANSTAAFL" Rich lynch@aristotle.ils.nwu.edu
-- 
John Burger                                               john@mitre.org

"You ever think about .signature files? I mean, do we really need them?"
  - alt.andy.rooney