From: Michael Greenberg
Subject: using the 'tagbody' feature of 'dolist'
Date: 
Message-ID: <mlg.679263056@lotus>
It's amazing that after extensively using Common Lisp for six years
one can still learn new 'features' of the language (I'm talking about
things in CLTL-I)

I just noticed that the body forms of dolist are in an implicit
tagbody.  I was wondering whether use of this feature is considered
good style.  If so, when. (I've never seen this feature used anywhere) 
I've used the the idiom

(dolist (x y)
  (block process-element
     ...
     (when ...
        (return-from process-element))
     ...))

I think it's that better (stylistically) then

(dolist (x y)
  process-next
    ...
    (when ...
	(go process-next))
    ...)

Do you agree?  [Why isn't (continue) in the language?]


Going back to the idea of learning new things about the language: Does
the experience of learning new features of CL happen to other VERY
experienced CL programmers out there?  If so, what does that say about
us and/or CL?



Michael Greenberg                      email: ··········@cadillac.siemens.com
Siemens Corporate Research             phone: 609-734-3347
755 College Road East
Princeton, NJ 08540
From: Barry Margolin
Subject: Re: using the 'tagbody' feature of 'dolist'
Date: 
Message-ID: <1991Jul12.080129.6360@Think.COM>
In article <·············@lotus> ···@lotus.siemens.com (Michael Greenberg) writes:
>I just noticed that the body forms of dolist are in an implicit
>tagbody.  I was wondering whether use of this feature is considered
>good style.  

Well, if you think goto's are OK style, then I suppose they're OK anywhere.

However, I think the implicit tagbody in DOLIST is mainly a holdover from
MacLisp.  In MacLisp, DOLIST was known to expand into a DO, which was known
to expand into a PROG, as this was the only efficient way to do looping and
variable binding (the only alternative was recursion, a la Scheme, but
MacLisp didn't do tail recursion optimization).  So, DO and its relatives
inherited the GO feature of PROG.

>	      If so, when. (I've never seen this feature used anywhere) 

Neither have I.

>I've used the the idiom
>
>(dolist (x y)
>  (block process-element
>     ...
>     (when ...
>        (return-from process-element))
>     ...))
>
>I think it's that better (stylistically) then
>
>(dolist (x y)
>  process-next
>    ...
>    (when ...
>	(go process-next))
>    ...)
>
>Do you agree?  

If these are supposed to be equivalent, the PROCESS-NEXT label should be at
the *bottom* of the DOLIST body, not the top.  The way it's written, (go
process-next) causes it to reprocess the current element.

I think the GO is better.  It took me several readings of the first example
before I realized it was supposed to be equivalent to the second.  I see
RETURN-FROM, and I naturally assume that we're exiting something; I had to
look carefully to realize that it's returning to somewhere inside the loop,
so the loop continues.  GO, on the other hand, doesn't have any such
connotations, so the reader is less likely to read it quickly and make
incorrect assumptions.

>		[Why isn't (continue) in the language?]

You'd also have to add names to the DO constructs, so you could write
(continue <name>).

Of course, you could always do this yourself with a macro:

(defmacro dolist-continuable (iter-spec &body body)
  (let ((label (gensym)))
    `(dolist ,iter-spec
       (flet ((continue () (go ,label)))
	 (tagbody .,body)) ; dolist-continuable should have implicit tagbody
       ,label)))

>Going back to the idea of learning new things about the language: Does
>the experience of learning new features of CL happen to other VERY
>experienced CL programmers out there?  If so, what does that say about
>us and/or CL?

I'm frequently surprised by how little of the language some people who have
been programming in CL for many years know (or at least use).

What it says about CL is that it is extremely powerful; what it says about
"us" is that most people can't be bothered to discover all its power.
Programmers are often more interested in the application domain than in the
tool, and I can appreciate that.  I'm not a researcher or scientist, so I
don't have an application domain that concerns me (although there are areas
I understand better than others and therefore prefer, such as OSes and user
utilities).  Furthermore, I happen to enjoy programming for its own sake.
I spend lots of time looking at and modifying existing code (much of what I
do is local customizations and bugfixes of vendor-supplied software), and
other forms of exploratory programming, so I get to see lots of different
coding styles and learn from them (both what to do and what *not* to do).

I think I can honestly say that there's nothing in CLtL1 that would
surprise me.  I'm *not* saying I know it by heart; I still sometimes have
to look up calling sequences and exact spellings of infrequently-used
functions (yesterday I tried to call list-difference, and then had to look
it up to find out it's named ldiff).  I also don't claim to be proficient
at using everything there; DEFINE-SETF-METHOD still confuses me sometimes,
and only a handful of people can get macro-defining-macro-defining-macros
right without pulling most of their hair out.  However, even though I've
been on X3J13 since its inception, I can't make the same claim for CLtL2;
I've not done much CLOS programming, for instance.
-- 
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar