the "loop" macro

275 views
Skip to first unread message

Ted Sandler

unread,
Aug 26, 2001, 12:55:55 AM8/26/01
to
Okay, is "loop" useful? Paul Graham mentions that the ANSI
specification is pretty vague on the specifics of "loop" and as such,
its use can't be recommended, etc.

-ted

Kent M Pitman

unread,
Aug 26, 2001, 1:59:02 AM8/26/01
to
Ted Sandler <tedsa...@rcn.com> writes:

It's controverisal, but my opinion is "yes, it's useful".

I used to not like it but was gradually won over, though I think good
style means avoiding using its total power and sticking to things that
are straightforward to read.

The reason some people don't like it is simple syntax--it's not grouped.
Something like
(loop for i from 0 to 100 for j from 3 for z in z-list do (something))
ought, some say, be grouped like
(loop (for i (from-to 0 100))
(for j (from 3))
(for z (in z-list))
(do (something)))
or at least
(loop :for ((i :from 0 :to 100)
(j :from 3)
(z :in z-list))
:do (something))
so that Emacs can more easily indent it or so that programs didn't need
a special parser to understand it. Nevertheless, loop advocates defend
the syntax as simple and important to be uncluttered by the extra parens.

Ignoring the syntax, though, and just accepting that it is what it is (and
what it has been for several decades), the fact is that it provides important
capabilities of concisely representing the generation and collection of
quantities in a very useful way. Not the only way that has ever been come
up with, but still *a* useful way.

For a long time, I preferred to write

(do ((l list (cdr l))
(result '() (cons (f (car l)) result)))
((null l) (nreverse result)))

But though this has the usefulness of paralleling Scheme's tail recursive

(let foo ((l list)
(result '()))
(if (null? l)
(reverse! result)
(foo (cdr l) (cons (f (car l)) result))))

in the end, I couldn't justify to new users why they shouldn't just write
the more obvious:

(loop for item in list
collect (f item))

And sure, you could also write

(mapcar #'f list)

but the point is that if you want to change the accumulation from collect
to max or min, you can't make a trivial edit to fix that, whereas with the
loop one you can do

(loop for item in list
maximize (f item))

Likewise, things like dolist only make it easy to step the easily-steppable
data structures. If you wanted to step a package in synch with a counter,
you'd have to mix binders. e.g.,

(let ((i 0))
(do-external-symbols (s "COMMON-LISP")
(incf i))
i) => 978

Whereas with loop you can do this in a consolidated way:

(loop for symbol being the external-symbols of "COMMON-LISP"
count t)
=> 978

Basicallly, a lot of standard idioms are there and it's really quite
definitely worth being able to use it.

- - -

The other things that are controversial are the fact that some aspects
of LOOP seem unnecessary at first blush. It has conditionals, for
example. One is sometimes led to write

(loop for x in y
when (f x)
do (g x))

when one could as well write

(dolist (x y)
(when (f x)
(g x)))

Looking at such an example, one might ask why WHEN is there at all. But
the answer turns out to be that it's *very* hard to write a macro in CL
that has a "detached" piece of syntax. So you need to have a way to get
to the collect point, and it's often in a conditional. Consider:

(loop for x in y
when (f x)
collect (g x))

This one you can't write as

(dolist (x y)
(when (f x)
(collect (g x))))

Nor is there another macro (even LOOP) that you could substitute for dolist
that would make the "collect" part work. You *could* make a special
"collecting" macro, for example, that did

(collecting (result :type list)
(dolist (x y)
(when (f x)
(collect-into result (g x)))))

but already you're in a problem where you've detached the collection from
the generation, and if you have several of these to do they get harder
and harder.

The ability in loop to do even complex things like:

(loop for x in '(1 2 3 4 5 6 7)
when (evenp x)
collect x into evens
else
collect x into odds
finally
(return (values evens odds)))
=> (2 4 6), (1 3 5 7)

is considerably easier and clearer than some other alternatives.

Also, being able to vary the collection is handy. Consider:

(loop for x in '(a b (c d) e f)
when (atom x)
collect x
else
append x)
=> (A B C D E F)

Writing the equivalent in a dolist is trickier. Consider:

(let ((result '()))
(dolist (x '(a b (c d) e f))
(if (atom x)
(push x result)
(dolist (subx x)
(push subx result))))
(nreverse result))
=> (A B C D E F)

Now, personally, I have no trouble looking at either of these and seeing
the same thing, but I still have to admit that the LOOP form of it is
more instantly accessible not only to me but to newcomers.

Some don't like it because it seems very ALGOL-esque and they think
something Lispy would be better, but those of us who've "given in to
the dark side" basically acknowledge that sometimes other languages
have something to offer in terms of expression and it's better not to
fight things that don't seriously need fighting. People who WANT
to not use this are still free to, but those who like LOOP are not
idiots or crazy or possessed by the devil. They're just making an
engineering trade-off.

Some also don't like that there are occasionally obscure things in LOOP
you have to be careful of. It used to be in older dialects that
(loop collect x for i from 1 to 3)
would unintuitively return (1 2 3 4) because the collection came before
the iteration test, but
(loop for i from 1 to 3 collect x)
would return (1 2 3) as you might expect. In ANSI CL, we've added
constraints to LOOP that say the variable stepping clauses have to
precede the collection parts, so this can't happen. Nevertheless,
there may be a few ways you can still confuse yourself with LOOP.
For example, you might think
(loop with i = (random 100) for x from 1 to 10 do (print (list i x)))
and
(loop for i = (random 100) for x from 1 to 10 do (print (list i x)))
meant the same in English, but you *must* know that FOR means to do the
action every time around the loop, while WITH means to do it only once
before starting. This is a major difference but people who make the
mistake of thinking loop is "just English" are going to get confused
by "apparent synonyms" (a.k.a. "false cognates").

Good LOOP style means knowing what the words really mean, and that
means that although it seems like the best entry point for the novice,
novices need to be more cautious than anyone about its use. That
doesn't mean "don't use it", just "use it with care". Lisp may be great
for building AI things but it does not use AI as part of its own
semantics...

Hope that helps.

Boris Schaefer

unread,
Aug 26, 2001, 6:17:05 AM8/26/01
to
Kent M Pitman <pit...@world.std.com> writes:

| but the point is that if you want to change the accumulation from collect
| to max or min, you can't make a trivial edit to fix that, whereas with the
| loop one you can do
|
| (loop for item in list
| maximize (f item))

As long as we're on that topic: how can you have a (simple) loop that
maximizes return a compound structure instead of the maximized value?

Something like:

(defclass foo ()
((name :accessor name)
(weight :accessor weight)))

(let ((foo1 (make-instance 'foo :name "foo1" :weight 10))
(foo2 (make-instance 'foo :name "foo2" :weight 9)))
(loop for foo in (list foo1 foo2)
maximize (weight foo))

This will return 10. I want it to return foo1. Is there some easy
way to accomplish this with maximize?

--
bo...@uncommon-sense.net - <http://www.uncommon-sense.net/>

The opposite of a correct statement is a false statement. But the opposite
of a profound truth may well be another profound truth.
-- Niels Bohr

Erik Naggum

unread,
Aug 26, 2001, 5:38:49 AM8/26/01
to
* Ted Sandler <tedsa...@rcn.com>

> Okay, is "loop" useful? Paul Graham mentions that the ANSI
> specification is pretty vague on the specifics of "loop" and as such,
> its use can't be recommended, etc.

Unfortunately, Paul Graham is pretty vague on the _reasons_ he does not
like "loop", and as such, his recommendations cannot be trusted, etc.
Ignore his hostility towards it. "loop" is simply _way_ useful. If you
are blinded by an irrational desire for syntactic purity that is thwarted
by the slightly unusual "loop" form (which demonstrates excellently how
you can build mini-languages in macros in Common Lisp), maybe you are
better off looking at Scheme? Paul Graham has some pretty bizarre Scheme
envy, too, which is another reason not to trust his recommendations.
Scheme people hate iteration, except when they run around in perfect
circles, cursing and re-cursing Common Lisp's iteration constructs.

///

Marc Battyani

unread,
Aug 26, 2001, 8:45:42 AM8/26/01
to

"Erik Naggum" <er...@naggum.net> wrote

Seems surprising, but Paul Graham thinks Common Lisp sucks:

Some quotes from "Being Popular" by Paul Graham, March 2001 :

"The political correctness of Common Lisp is an aberration."

"A more serious problem is the diffuseness of prefix notation. For
expert hackers, that really is a problem. No one wants to write
(aref a x y) when they could write a[x,y]."

"The good news is, it's not Lisp that sucks, but Common Lisp."

The original is there : http://www.paulgraham.com/popular.html

OK, a last funny one:

"Using first and rest means 50% more typing. And
they are also different lengths, meaning that the arguments won't
line up when they're called, as car and cdr often are, in successive
lines. "

Sigh...

Marc


Kent M Pitman

unread,
Aug 26, 2001, 9:24:39 AM8/26/01
to
Boris Schaefer <bo...@uncommon-sense.net> writes:

> Kent M Pitman <pit...@world.std.com> writes:
>
> | but the point is that if you want to change the accumulation from collect
> | to max or min, you can't make a trivial edit to fix that, whereas with the
> | loop one you can do
> |
> | (loop for item in list
> | maximize (f item))
>
> As long as we're on that topic: how can you have a (simple) loop that
> maximizes return a compound structure instead of the maximized value?
>
> Something like:
>
> (defclass foo ()
> ((name :accessor name)
> (weight :accessor weight)))
>
> (let ((foo1 (make-instance 'foo :name "foo1" :weight 10))
> (foo2 (make-instance 'foo :name "foo2" :weight 9)))
> (loop for foo in (list foo1 foo2)
> maximize (weight foo))
>
> This will return 10. I want it to return foo1. Is there some easy
> way to accomplish this with maximize?

It's unfortunate that the ability to define other loop-paths was omitted
from the standard, since most implementations have such a thing.
Some things I think you have to just code longhand.

(loop with best-foo = nil ;untested


for foo in (list foo1 foo2)

when (or (not best-foo)
(> (weight foo) (weight best-foo)))
do (setq best-foo foo)
finally (return best-foo))

All in all, I think this is still pretty readable, though I'd accept
the classic

(let ((best-foo nil)) ;untested
(dolist (foo (list foo1 foo2))
(when (or (not best-foo)
(> (weight foo) (weight best-foo)))
(setq best-foo foo)))
best-foo)

as equally good in this case. LOOP isn't, as spec'd, a panacea
for everything. But its usefulness decays relatively gracefully,
allowing you to fall back on weaker clauses rather than just
having you fall out of it suddenly if you reach a thing you can't
do in the totally-easy way.

John Foderaro

unread,
Aug 26, 2001, 10:51:58 AM8/26/01
to
Someone has to speak for the people who dislike the loop macro so it might as well be
me.

The beauty of Lisp is that function follows form. The uninitiated often laugh at
all the parentheses in a Lisp function. The Lisp expert however sees in those parens
the structure of the code. It's like looking at the framework of a building being
built and being able to envision the function of every part of it.

The loop macro ruins this. You have an opening paren and a closing parens and then
a collection of english words with stuff in between. There is no longer any structure
visible. You have to read the form as you would a novel with very obscure
and convoluted sentence struture. (see http://www.bulwer-lytton.com/ for convoluted
sentence structure examples).

Everyone who've I've seen attracted to the loop macro starts out swearing that they
will only use it for simple loops but soon get loop fever and it's a challenge to them
to write the most obscure unreadable loop macros they can, using every single loop
macro keyword.

my advice: Avoid loop like the plauge. Stick with all those parens. Make it your
goal that your code will not only work but will be readable and modifyable by others.
Yes it may take more characters to write your code. So what. Yes you may find
yourself building the same frameworks over and over again (e.g. to collect results
from an iteration) but as Kent pointed out when you read this code you recognize
common idioms like this simply from the structure. In fact you can see what the code
is doing from the framework alone (the paren layout) without even reading what's
inside the parens.

Learn Lisp first. Give it a chance before you start in on the loop language.

-john foderaro
franz inc.

Jochen Schmidt

unread,
Aug 26, 2001, 11:16:18 AM8/26/01
to
John Foderaro wrote:

This is a reasonable statement against what may be seen bad with the LOOP
macro - but then I still do not understand how you could then recommend the
usage of your IF* macro which IMHO destroys too the structure of Lisp code
you speak above. With IF* it is even worse because probably through the
nature of it I've seen that often alot of "normal structured" Lispcode is
used between the THEN ELSE a.s.o. tags (sometimes more than fits on a
screen!!!). It has the same problems like LOOP with editors like EMACS
but brings IMHO not very much gain instead of a questionable kind of
syntactic sugar that could be better done by appropriate use of IF, UNLESS
and WHEN.

In your style-guide you furthermore advice against the usage of WHEN and
UNLESS with arguments that sound IMHO more plausible for Scheme then for
Common Lisp (IF, UNLESS and WHEN would be ambigous concepts)

For those that really want to avoid "unlispy syntax" I would recommend then
to avoid IF* and better use IF, WHEN and UNLESS appropriate and furthermore
use the ITERATE macro instead of the standard extended LOOP macro.

ciao,
Jochen

--
http://www.dataheaven.de

Jochen Schmidt

unread,
Aug 26, 2001, 11:31:30 AM8/26/01
to
Ted Sandler wrote:

I would say that LOOP is a immensily useful thing that can make certain
things alot easier to do (as Kent already pointed out).

I think the key is to recognize when _not_ to use LOOP.
It is imho nicer to write e. g.

(dolist (i '(1 2 3))
(print i))

than

(loop for i in '(1 2 3)
do (print i))

or

(dotimes (x width)
(dotimes (y height)
(setf (aref *map* x y) (+ x y))))

instead of

(loop for x from 0 below width
do (loop for y from 0 below height
do (setf (aref *map* x y) (+ x y))))

If you don't need the special accumulation features (collect, nconcing,
append, maximize...) or the more declarative arithmetic FOR loop:

(loop for i from m to n by o ...)

then it is probably a better idea to use the other facilities.

Kent M Pitman

unread,
Aug 26, 2001, 12:01:06 PM8/26/01
to
John Foderaro <j...@unspamx.franz.com> writes:

> Someone has to speak for the people who dislike the loop macro so
> it might as well be me.

Thanks for volunteering! It's hard to debate with "unnamed others".



> The beauty of Lisp is that function follows form.

"The". Hmm. Surely there are other beauties. Also, there are bound to be
exceptions, and I think there are good reasons to believe that LOOP and
FORMAT, with their "alternate languages", occur in places that one might
reasonably expect such exceptions to crop up.

I/O is quite complicated, yet not always "important" (in the sense of
wanting to be the visual focus). Yet in Maclisp before FORMAT was common,
the use of
(progn (terpri)
(princ '|There |)
(princ (cond ((= n 1) '|is|) (t '|are|)))
(princ '| |)
(let ((base 10)) (princ n))
(princ '| |)
(princ name)
(cond ((not (= n 1)) (princ '|s|)))
(princ '| here.|))
would completely dominate the landscape, making it hard to find the
computation. We still fall back to this kind of thing once in a while, but
we gave up our general syntax in the common case to gain something very
valuable: conciseness and focus.

Likewise, for iteration, the business of generating, filtering, and
accumulating is very heavily idiomatic and to go and *implement* it every
time instead of to call up the idiom makes it necessary for people to
repeat sometimes-obscure incantations that they ought not to have to know
and that sometimes might even improperly optimize for a given implementation.
I agree it loses a little of the elegance you cite, but not irrationally.
There is a very definite gain to be had.

> The uninitiated often laugh at
> all the parentheses in a Lisp function. The Lisp expert however sees in those parens
> the structure of the code.

Is this a proposal that the correct fix to LOOP is a different way to
parenthesize it? If not, it seems like smokescreen. If so, I'd be curious
to see your proposed parenthesization. I've found in my few tries that it's
painful to do because some groupings either divide things that ought not be
divided or don't divide things that ought. e.g.,
for x from 3 to 5
Should this be
(x (from 3) (to 5))
and if so what about the from-to relationship? or
(x (from-to 3 5))
in which case what about the (from 3)/(to 5) associations?

> Everyone who've I've seen attracted to the loop macro starts out
> swearing that they will only use it for simple loops but soon get
> loop fever and it's a challenge to them to write the most obscure
> unreadable loop macros they can, using every single loop macro
> keyword.

I've never seen this happen. We must have a non-overlapping set of
acquaintances.

> my advice: Avoid loop like the [plague]. Stick with all those parens.

But what goes in them? I posted several LOOP examples that I don't think
were candidates for any hypothetical obfuscated-lisp award. Perhaps you
could go through those and post your preferred alternative.

John Foderaro

unread,
Aug 26, 2001, 1:10:21 PM8/26/01
to
In article <9mb3r4$t1q$1...@rznews2.rrze.uni-erlangen.de>, j...@dataheaven.de says...

> This is a reasonable statement against what may be seen bad with the LOOP
> macro - but then I still do not understand how you could then recommend the
> usage of your IF* macro which IMHO destroys too the structure of Lisp code
> you speak above.

Destroys? I don't see that at all. In fact if indented properly
(we supply the emacs code to do this) then it actually displays
the structure of a conditional far better than any alternative.

Yes if* has english language 'keywords' (then, else and elseif)
but unlike loop you don't have to read the keywords to know
what the code does. They just exist to separate parts of
the conditional.

For example you can write (if* aaaaaa then bbbbbb else cccccc)
but you can't write (if* aaaaaa else cccccc then bbbbbb).
You know that after the predicate will be a 'then'. You don't
even have to read it. The 'else' is there just so you know
that cccccc doesn't follow bbbbbb which you don't see in
(if aaaaaa bbbbbb cccccc).
With loop you must read every keyword to understand what's going on.

Readability is in the mind of the reader. AllegroServe is an example
of a large program written in the style I prefer (no loop macro (other than the no
keyword version), no if, when and unless). Everyone can judge for themselves whether
this style works. (source available at ftp://ftp.franz.com/pub/aserve/ )

Christophe Rhodes

unread,
Aug 26, 2001, 1:39:36 PM8/26/01
to
Boris Schaefer <bo...@uncommon-sense.net> writes:

> Kent M Pitman <pit...@world.std.com> writes:
>
> | but the point is that if you want to change the accumulation from collect
> | to max or min, you can't make a trivial edit to fix that, whereas with the
> | loop one you can do
> |
> | (loop for item in list
> | maximize (f item))
>
> As long as we're on that topic: how can you have a (simple) loop that
> maximizes return a compound structure instead of the maximized value?
>

> This will return 10. I want it to return foo1. Is there some easy
> way to accomplish this with maximize?

It's not quite what you're asking, so raising this is this context is
perhaps a little cheeky, but my quest for making people aware of
wheels and reinvention leads me to suggest googling on
groups.google.com for "lisp morally-biggest" (this is not meant to be
intuitive), which will lead you to a dubious implementation of a
decent function. There were followups with better implementations
(O(n) rather than O(n^2), for instance).

Cheers,

Christophe
--
Jesus College, Cambridge, CB5 8BL +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/ (defun pling-dollar
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)

Jochen Schmidt

unread,
Aug 26, 2001, 1:49:16 PM8/26/01
to
John Foderaro wrote:

> In article <9mb3r4$t1q$1...@rznews2.rrze.uni-erlangen.de>, j...@dataheaven.de
> says...
>> This is a reasonable statement against what may be seen bad with the LOOP
>> macro - but then I still do not understand how you could then recommend
>> the usage of your IF* macro which IMHO destroys too the structure of Lisp
>> code you speak above.
>
> Destroys? I don't see that at all. In fact if indented properly
> (we supply the emacs code to do this) then it actually displays
> the structure of a conditional far better than any alternative.

This is a question of personal taste I fear - but IF* is definitely similar
controversial like the extended LOOP facility.

> Yes if* has english language 'keywords' (then, else and elseif)
> but unlike loop you don't have to read the keywords to know
> what the code does. They just exist to separate parts of
> the conditional.
>
> For example you can write (if* aaaaaa then bbbbbb else cccccc)
> but you can't write (if* aaaaaa else cccccc then bbbbbb).
> You know that after the predicate will be a 'then'. You don't
> even have to read it. The 'else' is there just so you know
> that cccccc doesn't follow bbbbbb which you don't see in
> (if aaaaaa bbbbbb cccccc).
> With loop you must read every keyword to understand what's going on.

in

(if aaaaaa then bbbbb elseif ccccc then ddddd else eeeee)

I have to read the keywords if I not indent the clauses appropriate (which
no bulk emacs will do right!)

But

(if aaaaa
bbbbb
(if ccccc
ddddd
eeeee))

is automaticall indented right by emacs

and even

(if aaaaa bbbbb (if ccccc ddddd eeeee))

is easier to glance at for me because the inner if is nested appropriately.

I see no real gain in doing it like IF* does - It did not happen very often
to me that I've written an IF were I really had to place an PROGN to
encapsulate the clauses. IMHO IF ic nicely indented by Emacs&Co. so that it
is pretty readable where the then and where the else clause is.

(if condition
(then-clause ..)
(else-clause ..))

against

(if* condition
then
(then-clause ..)
else
(else-clause ..))

Besides of the fact that it maks the code unnecessary longer it leads to
the problem that the clauses are indented on the same level. If the clauses
are a bit bigger than shown here the little else is visually vanishing
between.

> Readability is in the mind of the reader. AllegroServe is an example
> of a large program written in the style I prefer (no loop macro (other
> than the no
> keyword version), no if, when and unless). Everyone can judge for
> themselves whether
> this style works. (source available at ftp://ftp.franz.com/pub/aserve/ )

Yes I know - and since I spent enough time with AllegroServe to port it to
e. g. LispWorks I can say that IF* is most of the times more difficult to
decipher for at least me and up to now all other contributors I've spoken
to.
For Portable AllegroServe we have chosen to let the IF* that are already in
unchanged since changing it would be more hassle than ignoring it. But
we've chosen too that all new written/rewritten code avoids the use of IF*
and use extended LOOP too where appropriate (since e. g. the use of the
simple LOOP is in most cases a bad decision since it hides the iteration to
deeply in the code).

Please see this as constructive critique - I'm telling you only of my
experience with e. g. IF* in general and besides that AllegroServe. I think
it is a good thing to get response - if it's positive or negative.

John Foderaro

unread,
Aug 26, 2001, 1:51:26 PM8/26/01
to

I'm not trying to join a debate on loop. I just wanted to present the other side of
the intelligent people can then weigh the arguments on both sides.

I'm not suggesting that loop can be fixed either by adding parenthesis or coming up
with ways of indenting it to make it understandable. It's a lost cause.


There is a point to be made about this though:

==== from kmp:

Yet in Maclisp before FORMAT was common,
the use of
(progn (terpri)
(princ '|There |)
(princ (cond ((= n 1) '|is|) (t '|are|)))
(princ '| |)
(let ((base 10)) (princ n))
(princ '| |)
(princ name)
(cond ((not (= n 1)) (princ '|s|)))
(princ '| here.|))

==== end kmp

I believe that what you are saying is the format in Common Lisp introduced a new
language to save us from having to do I/O like above, and since that was a good thing
then maybe loop's introduction of a new language for iteration is a good thing as well
too.

Let's look at your example though. It took you very little time to write that after
knowing what you wanted it to do, and I'm sure that everyone read it very quickly and
figured out what it did instantly.

Now I challenge everyone to write the equivalent using Format. Time yourself to see
how long it takes.

<i'll pause here while you go do it>
..
..
..
..


Time's up..

here's my solution with a test case (i'm sure there are other ways of doing it)

(format t "There ~[are~;is~:;are~] ~:*~d ~a~2:*~p here." 1 'ball)

Can you read it and tell me without trying it whether it works or not?
Give it to a co-worker who hasn't seen this thread and ask him/her what it prints? How
long until you get an answer?

There's no question that the format string is more concise. But is using it better?
Is writing code with the least number of characters always best or is it important to
write code that others can read and understand without reaching for the Lisp manual.


Another great example from kmp:

=== from kmp

For example, you might think
(loop with i = (random 100) for x from 1 to 10 do (print (list i x)))
and
(loop for i = (random 100) for x from 1 to 10 do (print (list i x)))

meant the same in English, [but they don't do the same thing in loop]

=== end kmp

loop lulls you into thinking that you understand the program since you understand
English. Make no mistake about it, loop is its own language. If you use it you
condem everyone who reads the code to also learn the loop language.


-john foderaro
franz inc

John Foderaro

unread,
Aug 26, 2001, 2:41:31 PM8/26/01
to
I do appreciate constructive criticism.

Just as an example to the others about what we're talking about I took a code segment
out of AllegroServe wrapped in a defun for realism and I'll show you what it looks
like with if* (the foo function) and if (the bar function).
One of the problems I have with the if special form occurs at the of the bar
function. It's pretty easy to get confused and think that the dotimes at the end is
always executed. At first glance you may not see the indentation difference between
the if and dotimes. I've seen code where people put in comments like ";else" before
such a clause since they see the problem too. All if* does is enforce that 'else'
comment (in effect).

(defun foo ()
(if* text-mode
then
; here is where we should do
; external format processing
#+(and allegro (version>= 6 0 pre-final 1))
(multiple-value-setq (buffer items tocopy)
(octets-to-string
mpbuffer
:string buffer
:start cur
:end (+ cur tocopy)
:string-start start
:string-end (length buffer)
:external-format external-format
:truncate t))
#-(and allegro (version>= 6 0 pre-final 1))
(dotimes (i tocopy)
(setf (aref buffer (+ start i))
(code-char (aref mpbuffer (+ cur i)))))
else
(dotimes (i tocopy)
(setf (aref buffer (+ start i))
(aref mpbuffer (+ cur i))))))


(defun bar ()
(if text-mode
(progn
; here is where we should do
; external format processing
#+(and allegro (version>= 6 0 pre-final 1))
(multiple-value-setq (buffer items tocopy)
(octets-to-string
mpbuffer
:string buffer
:start cur
:end (+ cur tocopy)
:string-start start
:string-end (length buffer)
:external-format external-format
:truncate t))
#-(and allegro (version>= 6 0 pre-final 1))
(dotimes (i tocopy)
(setf (aref buffer (+ start i))
(code-char (aref mpbuffer (+ cur i))))))

(dotimes (i tocopy)
(setf (aref buffer (+ start i))
(aref mpbuffer (+ cur i))))))

Thomas F. Burdick

unread,
Aug 26, 2001, 3:38:59 PM8/26/01
to
John Foderaro <j...@unspamx.franz.com> writes:

> loop lulls you into thinking that you understand the program since
> you understand English. Make no mistake about it, loop is its own
> language. If you use it you condem everyone who reads the code to
> also learn the loop language.

This is only a problem if you foolishly assume that loop is English.
It's ALGOL-inside-Lisp, which is a great example of how Common Lisp
tries to support a variety of styles. Personally, I tried to suck in
my Algol-like-languages gut until I really got a feel for programming
in lisp, but now I love that I can let it hang out. I would expect
that people who spent less time in Algol-like languages would think in
Algol-ish terms less, and thus find less of a need for loop. The same
as how people who grew up in Smalltalk are going to eat up CLOS, and
spend a lot more of their time writing in CLOS, than others.

My natural instinct is to throw a bunch of different styles at a
problem and use what sticks. I'll occasionally go thousands of lines
without a loop form, but when it sticks, I use it.

Coby Beck

unread,
Aug 26, 2001, 3:46:13 PM8/26/01
to
loop is an excellent tool. But like a good drug, it is easily abused!

I agree that it's syntax is rather a different breed from the rest of
lisp... but one thing it shares with the language as a whole is the freedom
to abuse its features. I've always thought loop gives you more rope than
you'll probably ever need, certainly more than enough to hang yourself!

As strictly "newbie" advice, I would say make sure your problem can't be
solved easily with mapcar, dotimes or dolist first, but if loop makes it
easier why hobble yourself?

Coby
--
(remove #\space "coby . beck @ opentechgroup . com")

"Ted Sandler" <tedsa...@rcn.com> wrote in message
news:3B88815A...@rcn.com...

Marco Antoniotti

unread,
Aug 26, 2001, 4:03:22 PM8/26/01
to

John Foderaro <j...@unspamx.franz.com> writes:

...

> Everyone who've I've seen attracted to the loop macro starts out
> swearing that they will only use it for simple loops but soon get
> loop fever and it's a challenge to them to write the most obscure
> unreadable loop macros they can, using every single loop macro
> keyword.
>
> my advice: Avoid loop like the plauge.

Ahem! ... and then use IF* when working with ACL?

Sorry, I couldn't resist. :)

Cheers

--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.

Kent M Pitman

unread,
Aug 26, 2001, 4:24:04 PM8/26/01
to
John Foderaro <j...@unspamx.franz.com> writes:

> (format t "There ~[are~;is~:;are~] ~:*~d ~a~2:*~p here." 1 'ball)

You've made it artificially hard and you seem to think this would make it
hard to write. You *can* do it that way, but you don't have to. Anyone
who is straining will not spend a long time looking up hard ways, they'll
do it the same easy way I'd have written:

(format t "There ~:[are~;is~] ~D ~A~P here." (= n 1) n name n)

> Can you read it and tell me without trying it whether it works or not?

No, but I can trivially vary the args and execute it in an interactive
environment to see if it works, and thereafter I can just glance at it and
say "seems like it's doing the right thing, glad it's not taking up much
space".

> There's no question that the format string is more concise. But is
> using it better?

You lived through those days of Maclisp and its companion dialect
"Franz Lisp" (no relation to Allegro CL for those of you who weren't
there). I'm surprised you can ask this. I still have my old code
listings and it's obvious at even just a glance that this was a change
100% for the better. No question. It's like the change from Assembly
language to a higher level language. Formatted I/O is nitpicky and
you can either let it take over your visual space or you can beat it
into submission by a compaction technology like this; I vote for the
latter. But we didn't quash the long-winded way in the process; we
retained both styles and people always have the option. It's *plain*
by inspecting the code of most people these days that we made a good
choice giving people this option; moreover, for those who aren't
satisfied there are other alternatives.

I'm not advocating LOOP-only nor FORMAT-only. I'm advocating that they
are well-placed in the language because they appeal to a large audience,
and I'm further arguing that that audience is not characterized by the
oversimplistic attribute "tasteless". There are good and even tasteful
reasons for using both of these. Using LOOP and FORMAT certainly do
not uniquely define taste. I'm not arguing that your desire to use
something else is tasteless. I'm not arguing that there weren't aesthetic
trade-offs made. But I think it goes a little far to say "avoid it like
the plague".

> Is writing code with the least number of characters always best

Absolutely not. But I haven't argued that. I have argued that code which
reasonably focuses the reader on things the reader cares about is important.
For example, LOOP's ability to name intent ("collect", "maximize", etc.)
is a virtue independent of code length that is lost in other variants of
code which might "implement" but not "express" that idea. In particular,
the idiom of push-push-push-nreverse cannot be argued, I finally decided of
my own code (which used to use this heavily), to be perspicuous as to the
fact of its collection of a forward list. It's an idiom that implements
the collection of a forward list but it looks weird as all get-out. LOOP
fixes that by hiding whatever accumulation technique it uses. Further, LOOP
*also* allows implementational flexibility to do better than I would have
done, and that is also an aesthetic which goes beyond simple numbers of
characters.

> or
> is it important to write code that others can read and understand
> without reaching for the Lisp manual.

You set up the straw man of the hard to read FORMAT string, but I don't
think it has to be that way. I think people should try to keep things
simple. And I often resort to combinations of Lispy iterative techniques
and FORMAT rather than use some of the more baroque list and conditional
accessors. However, I don't mind it when others don't; I trust them to
have debugged what they did (partly) and when I don't I just construct
a test case, which usually is quite easy.

> Another great example from kmp:
>
> === from kmp
>
> For example, you might think
> (loop with i = (random 100) for x from 1 to 10 do (print (list i x)))
> and
> (loop for i = (random 100) for x from 1 to 10 do (print (list i x)))
> meant the same in English, [but they don't do the same thing in loop]
>
> === end kmp
>
> loop lulls you into thinking that you understand the program since
> you understand English. Make no mistake about it, loop is its own
> language.

We do agree on this code being something you have to learn to read,
but I think this is a manageable risk.

> If you use it you condem everyone who reads the code to
> also learn the loop language.

Somewhat. Though mostly only if really trying to debug the code. Code
will often have tremendous subtlety that one doesn't see at first blush.
One usually just goes ahead and glances at it and trusts it until one
zooms in--and I find it helpful if, when in this mode of scanning from
high above, like a bird looking for a place to land, if the general
landmarks are clearly marked. LOOP does that. It draws my eye to the
fact that a list traversal is happening, or a count is being done, etc.
Then I can debug it if I have to, but that's very useful skimming info.
So there are two issues: how do I debug a LOOP (which I agree can involve
a bit of care) and how do I let a probably-debugged LOOP guide me (which
can help a lot, though if it's not really debugged can be confusing).
Still, merely learning "caution" in over-believing LOOP is important.

Btw, one other factor we didn't mention and that's debugging. The only
way to debug an out-of-control LOOP is by macroexpanding it. You can't
always visually step it (though modern LOOP can do this a little easier
than some of the earlier LOOP variants you and I grew up on). I agree
that's an issue, but again I think it's manageable.

Lieven Marchand

unread,
Aug 26, 2001, 10:42:34 AM8/26/01
to
Kent M Pitman <pit...@world.std.com> writes:

> Boris Schaefer <bo...@uncommon-sense.net> writes:
> > As long as we're on that topic: how can you have a (simple) loop that
> > maximizes return a compound structure instead of the maximized value?
>

> It's unfortunate that the ability to define other loop-paths was omitted
> from the standard, since most implementations have such a thing.

I agree to the point that I load the MIT-LOOP code in Lispworks and
shadow CL:LOOP and CL:LOOP-FINISH, but I don't see how add-loop-path
can be used to solve this problem.

--
Lieven Marchand <m...@wyrd.be>
She says, "Honey, you're a Bastard of great proportion."
He says, "Darling, I plead guilty to that sin."
Cowboy Junkies -- A few simple words

Hannu Koivisto

unread,
Aug 26, 2001, 4:47:28 PM8/26/01
to
Kent M Pitman <pit...@world.std.com> writes:

| John Foderaro <j...@unspamx.franz.com> writes:
...

| Is this a proposal that the correct fix to LOOP is a different way to
| parenthesize it? If not, it seems like smokescreen. If so, I'd be curious
| to see your proposed parenthesization. I've found in my few tries that it's

Are you aware of Iterate
<http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/iter/iterate/0.html>?
(The distribution archive contains two Postscript documents (the
manual and "Don't Loop, Iterate" paper) that make good reading for
those unfamiliar with the package.) I think it comes pretty close
to a nice "parenthesized LOOP". Then again, I also think it is
even too close to a parenthesized LOOP in some ways.

| painful to do because some groupings either divide things that ought not be
| divided or don't divide things that ought. e.g.,
| for x from 3 to 5
| Should this be

IMO, there are two alternatives depending on how generic FOR you
want. If you want a LOOP-like FOR that can assign to the given
variable numbers of some range, elements of a list, vector etc., I
think your example should be:

(for x (scan-range :from 3 :to 5))

The version for the elements of a list would be:

(for x (scan '(1 2 3)))

If you know Series, you should realize that what I just depicted is
FOR that assigns to its first argument elements of series given as
its second argument. FWIW, I might have used shorter RANGE instead
of SCAN-RANGE if I didn't want to use existing scanners from the
Series package. Also note that I'm not saying this is what I think
the full Series-FOR syntax should be; it is just what is needed to
handle your example.

If you don't want that generic FOR, then I think your example
should/could be:

(for x :from 3 :to 5)

While you _could_ make this kind of FOR at least as generic as
LOOP's FOR (obviously not as generic as the Series-FOR above,
though), I think it would be a bad idea. A better idea would
probably be to have a separate form (actually, more than one form
might be needed) for iterating over the elements of different
containers.

| > my advice: Avoid loop like the [plague]. Stick with all those parens.
|
| But what goes in them? I posted several LOOP examples that I don't think
| were candidates for any hypothetical obfuscated-lisp award. Perhaps you
| could go through those and post your preferred alternative.

I haven't read the whole thread but I'm sure those examples would
be handled nicely by Iterate.

--
Hannu

Erik Naggum

unread,
Aug 26, 2001, 5:16:26 PM8/26/01
to
* John Foderaro <j...@unspamx.franz.com>

> You have an opening paren and a closing parens and then a collection of
> english words with stuff in between. There is no longer any structure
> visible. You have to read the form as you would a novel with very
> obscure and convoluted sentence struture.

Yeah, ick! That description kind of reminds me of stuff like this:

(if* (not (probe-file orig-dxl))
then (setq prev (rename-file dxl-file orig-dxl))
elseif (not (probe-file old-dxl))
then (setq prev (rename-file dxl-file old-dxl)))

> Everyone who've I've seen attracted to the loop macro starts out swearing
> that they will only use it for simple loops but soon get loop fever and
> it's a challenge to them to write the most obscure unreadable loop macros
> they can, using every single loop macro keyword.

You have seen my code. I do not do that. I have seen lots of other
people's code, and they do not do the horrible things you conjure up.
Please do not insult people's intelligence so gravely by pretending that
you do not know that you exaggerate wildly and irrationally and that you
think nobody would be smart enough to arrest you for it. They do, and it
makes your point ridiculous and dishonest. Coupled with the fact that
you do use that fantastic if* monster, which suffers from even more of
the problems you have described for loop, the intelligent reader will sit
back and wonder what the hell you _really_ are opposed to about loop as
none of your lofty principles apply to another obvious candidate.

> My advice: Avoid loop like the plauge. Stick with all those parens.


> Make it your goal that your code will not only work but will be readable
> and modifyable by others.

Excellent argumentation, and I mean that. Pity it is not applied to if*,
too, which is such an incredibly horrible concoction that I have a really
hard time dealing with those who use it, and not just their code. Unlike
loop, which does some pretty useful things, if* is but a wrapper around
cond to get rid of progn, making your code unreadable and unmodifiable by
those who happen to think that this is good advice, slightly paraphrased:

> Learn Lisp first. Give it a chance before you start in on the if* language.

Please get rid of if* in published Franz Inc code, and I can live with
your verbose iteration idioms and the moderately supported fear that loop
is underoptimized for political reasons. When you have cleaned up the
if* act, I will probably listen to you on a lot of other issues, too, but
as long as you rant and rave about loop while you use if*, I am sorry,
but I cannot take you very seriously. It looks too much like a religious
issue that has none of the redeeming qualities of actual religions.

///

Gareth McCaughan

unread,
Aug 26, 2001, 5:25:22 PM8/26/01
to
John Foderaro wrote:

> One of the problems I have with the if special form occurs at the of the
> bar function. It's pretty easy to get confused and think that the dotimes
> at the end is always executed. At first glance you may not see the
> indentation difference between the if and dotimes.

where the BAR function looks, in outline, like this.

(defun bar ()
(if something
stuff-to-do-when-true
stuff-to-do-when-false))

It seems to me that the blame here lies not with IF, but
with the peculiar convention, which I have never understood,
that indents the "then" and "else" parts of an IF differently.
It would almost make sense if the "else" part of an IF had an
implicit PROGN, but it doesn't.

With indentation more like

(defun bar ()
(if something
stuff-to-do-when-true
stuff-to-do-when-false))

it is much harder to miss the fact that the two consequent
clauses are indented by the same amount.

Perhaps someone can enlighten me. Why is IF so often indented
in this strange way? (Non-answer: "Because that's what emacs
lisp-mode does." So, why does emacs lisp-mode do it?)

In the particular case John Foderaro posted, the stuff-to-do-when-true
is moderately long (17 lines). If that's too long to be able to see
how the indentation lines up, well, that's a pity, but that sort of
issue arises absolutely all the time and there ought to be better
solutions than changing the syntax. Do we need a new syntax to
replace LET, with explicit end-of-scope markers? A new syntax for
function call, so you can't get confused about what function any
given thing is an argument to? That way lie XML and madness...

--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc

Gareth McCaughan

unread,
Aug 26, 2001, 5:41:47 PM8/26/01
to
John Foderaro quoted Kent Pitman's pre-FORMAT code sample

> (progn (terpri)
> (princ '|There |)
> (princ (cond ((= n 1) '|is|) (t '|are|)))
> (princ '| |)
> (let ((base 10)) (princ n))
> (princ '| |)
> (princ name)
> (cond ((not (= n 1)) (princ '|s|)))
> (princ '| here.|))

and a typical equivalent using FORMAT

> (format t "There ~[are~;is~:;are~] ~:*~d ~a~2:*~p here." 1 'ball)

and challenged:

> Can you read it and tell me without trying it whether it works or not? Give
> it to a co-worker who hasn't seen this thread and ask him/her what it prints?
> How long until you get an answer?
>
> There's no question that the format string is more concise. But is using it
> better? Is writing code with the least number of characters always best or
> is it important to write code that others can read and understand without
> reaching for the Lisp manual.

I think John may be missing Kent's key point.

When you write something using FORMAT, it may be harder to
read. But, by being concise, it renders the surrounding code
easier to read. The code Kent cited is certainly easier to
check than John's version using FORMAT; but embed it, along
with a few similar fragments, into something else, and *the
whole of the something-else will become hard to read*. This
is a worthwhile trade-off only if the details of the output
are more important than the computation in which it's embedded.

Even if using obscure features of FORMAT is deemed evil,
it's possible to improve considerably on the fully explicit
code Kent posted by using FORMAT more simply.

(format t "~&There ~A ~D ~A~A here."
(if (= n 1) "is" "are")
n name
(if (= n 1) "" "s"))

Incidentally, John's code is not equivalent to Kent's; it's
missing an equivalent of the (TERPRI) at the start. I think
this is an indication that fully-written-out code is not as
much easier to read as one might think.

Kent M Pitman

unread,
Aug 26, 2001, 6:10:26 PM8/26/01
to
Lieven Marchand <m...@wyrd.be> writes:

> Kent M Pitman <pit...@world.std.com> writes:
>
> > Boris Schaefer <bo...@uncommon-sense.net> writes:
> > > As long as we're on that topic: how can you have a (simple) loop that
> > > maximizes return a compound structure instead of the maximized value?
> >
> > It's unfortunate that the ability to define other loop-paths was omitted
> > from the standard, since most implementations have such a thing.
>
> I agree to the point that I load the MIT-LOOP code in Lispworks and
> shadow CL:LOOP and CL:LOOP-FINISH, but I don't see how add-loop-path
> can be used to solve this problem.

Hmm. I haven't looked recently. You're probably right that
add-loop-path per se can't. I was speaking more generally to the
issue of adding loop keywords, by which I also meant different
accumulators. If the loop path stuff couldn't do that, I was in
error. Consider my remarks to be revised to say just that I think
it's unfortunate that LOOP isn't extensible.

Kent M Pitman

unread,
Aug 26, 2001, 6:22:08 PM8/26/01
to
Gareth.M...@pobox.com (Gareth McCaughan) writes:

> John Foderaro wrote:
>
> > One of the problems I have with the if special form occurs at the of the
> > bar function. It's pretty easy to get confused and think that the dotimes
> > at the end is always executed. At first glance you may not see the
> > indentation difference between the if and dotimes.
>
> where the BAR function looks, in outline, like this.
>
> (defun bar ()
> (if something
> stuff-to-do-when-true
> stuff-to-do-when-false))
>
> It seems to me that the blame here lies not with IF, but
> with the peculiar convention, which I have never understood,
> that indents the "then" and "else" parts of an IF differently.

One historical reason for this is that in some Lisp dialects (Lisp
Machin Lisp, I believe, and maybe others) there was an IF that took
(IF test then &body else)
so there the back-indentation helped you know when you were in the "body".
You were supposed to put your "short" side of the test first.

Another reason is that people get confused when they see:

(if (a b c d) (e f (g h) (i j (k l)) (m n)) (o p (q r) (s t)))

as to where the THEN and ELSE are. So if you put your cursor after the
IF in emacs and do C-M-f LINEFEED C-M-f LINEFEED you'll get the right
indentation AND it will be "obvious" to someone reading that line 3
of the new expression ("programs count from 0, people count from 1")
begins the else part. AND moreover, you can check the "correctness"
of this "visual claim" by pressing TAB on that line and seeing that
the line does not move.

(if (a b c d)
(e f (g h) (i j (k l)) (m n))
(o p (q r) (s t)))

> It would almost make sense if the "else" part of an IF had an
> implicit PROGN, but it doesn't.

Historically, it was. And people didn't want a billion different lisp modes.

Although if you look at my code, you'll see that it always starts with

;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Package: CL-USER; -*-

(in-package "CL-USER")

both because the Syntax info has programmatic effect on Symbolics (selecting
a sub-mode of Lips mode) and because it's a nice declarative piece of info.

(All of that notwithstanding, though, I still prefer the balanced indenting
of if, and I am constantly nudging those little else parts back over to be
lined up underneath the then part in my own code when using Emacs because
I've been too lazy to work out the init-file setup to make it indent in
the way I think of as "right".)


Thomas F. Burdick

unread,
Aug 26, 2001, 6:56:51 PM8/26/01
to
Kent M Pitman <pit...@world.std.com> writes:

That's pretty funny, given how happy you are to be a part of usenet's
collective Lisp knowledge, that you don't try to take advantage of
usenet's emacs knowledge. I guess it's one of those things you only
think of when you're about to hit `space', which means you're in the
middle of something more important. Try adding this to your .emacs
file, see how you like it:
(add-hook 'lisp-mode-hook
#'(lambda ()
(setq lisp-indent-function 'common-lisp-indent-function)))

John Foderaro

unread,
Aug 26, 2001, 6:59:57 PM8/26/01
to
In article <sfwlmk6...@world.std.com>, pit...@world.std.com says...

> John Foderaro <j...@unspamx.franz.com> writes:
>
> > (format t "There ~[are~;is~:;are~] ~:*~d ~a~2:*~p here." 1 'ball)
>
> You've made it artificially hard and you seem to think this would make it
> hard to write. You *can* do it that way, but you don't have to. Anyone
> who is straining will not spend a long time looking up hard ways, they'll
> do it the same easy way I'd have written:
>
> (format t "There ~:[are~;is~] ~D ~A~P here." (= n 1) n name n)
>
>

I was just trying to go along with the point you were making: format introduces a new
language just for controlling I/O. So I used that language to its fullest extent.
Imagine if 'n' and 'name' in your example were computed values. You would have to
change your code to let bind variables to the computation of those values. I wouldn't
have to change a thing. I thought that's the point you were getting at when you
mentioned the power of an imbedded I/O language (which effectively has a let form
since you can go back to certain argument values repeatedly).

Your use of format is so simple that there are plenty of other ways to do what you've
done that don't require an imbedded I/O language. Back in the old Franz Lisp days I
had a 'msg' macro that expanded into a sequence of print's of its arguments. So I
would write something like

(msg :newline "There " (if* (= n 1) then "are" else "is") " " n " "
name (if* (not (= n 1)) then "s" else "") " here.")

This has too much code but one could imagine extending the msg macro so you could
write
(msg :newline "There " (:bool (= n 1) "are" "is") " " n " " name (:plural n) " here.")

The advantage here is that it stays all in Lisp. I could do real lisp iteration
in the middle of the stuff being printed and then revert back to printing mode inside
the iteration using the msg macro again (for anyone who has used the htmlgen html
printer inside AllegroServe it's the same idea).

Kent M Pitman

unread,
Aug 27, 2001, 12:31:19 AM8/27/01
to
t...@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> That's pretty funny, given how happy you are to be a part of usenet's
> collective Lisp knowledge, that you don't try to take advantage of
> usenet's emacs knowledge. I guess it's one of those things you only
> think of when you're about to hit `space', which means you're in the
> middle of something more important. Try adding this to your .emacs
> file, see how you like it:
> (add-hook 'lisp-mode-hook
> #'(lambda ()
> (setq lisp-indent-function 'common-lisp-indent-function)))

Heh. That's true about when you feel the aggravation and how quickly
it passes. But also, the other thing that keeps me from doing it is
the knowledge I have the fix in any of seventeen files already locally
on my disk--just misplaced. (I don't think this is the fix I have; I
think I have a specific list of indent rules.) But I hate asking
questions I already have the answer to--knowing that it generates work
for someone to post a response to a question, I try to keep my
questions to a minimum... But since you volunteer the info, sure,
I'll give it a go. Thanks. :-)

Raymond Wiker

unread,
Aug 27, 2001, 3:48:30 AM8/27/01
to
Gareth.M...@pobox.com (Gareth McCaughan) writes:

> Perhaps someone can enlighten me. Why is IF so often indented
> in this strange way? (Non-answer: "Because that's what emacs
> lisp-mode does." So, why does emacs lisp-mode do it?)

Because emacs-lisp is one of those lisps that has an implicit
progn around the else part, I guess :-)

--
Raymond Wiker
Raymon...@fast.no

Dorai Sitaram

unread,
Aug 27, 2001, 11:23:51 AM8/27/01
to
In article <9mbcpu$4ht$1...@rznews2.rrze.uni-erlangen.de>,

Jochen Schmidt <j...@dataheaven.de> wrote:
>John Foderaro wrote:
>
>> In article <9mb3r4$t1q$1...@rznews2.rrze.uni-erlangen.de>, j...@dataheaven.de
>> says...
>>> This is a reasonable statement against what may be seen bad with the LOOP
>>> macro - but then I still do not understand how you could then recommend
>>> the usage of your IF* macro which IMHO destroys too the structure of Lisp
>>> code you speak above.
>>
>> Destroys? I don't see that at all. In fact if indented properly
>> (we supply the emacs code to do this) then it actually displays
>> the structure of a conditional far better than any alternative.
>
>This is a question of personal taste I fear - but IF* is definitely similar
>controversial like the extended LOOP facility.

IF* looks like COND where some parens have been
replaced by keywords. LOOP, on the other hand,
is completely novel.

So if IF* has the advantage of being recognizable as
something else that is already known, then LOOP
doesn't have that advantage. And if LOOP has the
advantage of being a truly new (i.e., different from
the rest) syntactic paradigm, then IF* doesn't have
that advantage. Thus, it's possible for IF* and LOOP
to raise different (or at least only partially
overlapping) sets of hackles.

--d

Jochen Schmidt

unread,
Aug 27, 2001, 12:18:04 PM8/27/01
to
Dorai Sitaram wrote:

Note that I did not say "IF* is definitely because of the same reasons
controversial like LOOP" but

"IF* ist definitely similar controversial like the extended LOOP facility."

The emphasis is on "similar controversial" and not "because of similar
reasons controversial"!

I personally like LOOP and dislike IF* and JKF seems to like IF* and
dislike LOOP - so it should be clear that there must be different reasons
for the critique _why_ IF* is a bad idea _even if_ LOOP is ruled as a good
idea.

The only questionable thing is if someone proposes so much the "Lisp-like"
syntax that he would rule out LOOP then it is not directly understandable
why he then chooses to add keywords to IF!

The difference is simply that I dislike IF* because I see no gain from
using it instead of WHEN, UNLESS, IF, COND... and I like LOOP not because
of it's fancy syntax but of the many possibilities it offers! (I personally
would prefer ITERATE over LOOP but the gain of ITERATE was up to now not
enough to overweight the fact that LOOP is standard)

John Foderaro

unread,
Aug 27, 2001, 1:02:52 PM8/27/01
to
In article <9mdrrc$eqm$1...@rznews2.rrze.uni-erlangen.de>, j...@dataheaven.de
says...

> The only questionable thing is if someone proposes so much the "Lisp-like"
> syntax that he would rule out LOOP then it is not directly understandable
> why he then chooses to add keywords to IF!
>

If you don't understand why it's not because I haven't tried repeatedly to
explain why. I even have a web page explaining it and I'm sure you've seen
references to it in my source code.

http://www.franz.com/~jkf/coding_standards.html

Geoff Summerhayes

unread,
Aug 27, 2001, 1:32:21 PM8/27/01
to

"Kent M Pitman" <pit...@world.std.com> wrote in message
news:sfwlmk6...@world.std.com...

> John Foderaro <j...@unspamx.franz.com> writes:
>
> > (format t "There ~[are~;is~:;are~] ~:*~d ~a~2:*~p here." 1 'ball)
>
> You've made it artificially hard and you seem to think this would make
it
> hard to write. You *can* do it that way, but you don't have to.
Anyone
> who is straining will not spend a long time looking up hard ways,
they'll
> do it the same easy way I'd have written:
>
> (format t "There ~:[are~;is~] ~D ~A~P here." (= n 1) n name n)
>

I can't resist going from the sublime to the ridiculous. After
visiting the 99 bottles page I noticed they had a program for
CL and one for CLOS but none that really exercised format. So
I rolled up my newbie sleeves and came up with this (and as a
bonus, it even uses loop):

(defun bottle-song (x &optional (stream t))
(format stream "~{~&~[~^~:;~:*~@(~R~) bottle~:*~P of ~
beer on the wall~:*~[.~:;,~%~:*~@(~R~) bottle~:*~P ~
of beer.~%You take one down, pass it around,~%~
~[No~:;~:*~@(~R~)~] bottle~:*~P of beer on the ~
wall.~%~%~:*~]~]~}"
(loop for i from x downto 0 collect i)))

(bottle-song 99)

-----------
Idle hands, etc. :-)

Geoff

Tim Moore

unread,
Aug 27, 2001, 2:40:14 PM8/27/01
to
On Sun, 26 Aug 2001, John Foderaro wrote:

> Everyone who've I've seen attracted to the loop macro starts out swearing that they
> will only use it for simple loops but soon get loop fever and it's a challenge to them
> to write the most obscure unreadable loop macros they can, using every single loop
> macro keyword.

Fuck that! The main reason to use loop is for the complicated cases. You
use it for the simple cases too in order to keep in practice.

Tim


Jochen Schmidt

unread,
Aug 27, 2001, 5:13:44 PM8/27/01
to
John Foderaro wrote:

I know this document and already noted that fact earlier - but I still feel
free to disagree on your rationale...

Richard Krush

unread,
Aug 28, 2001, 5:15:36 AM8/28/01
to

I apologize for intruding with off-topic question, but is this supposed
to make the ELSE-clause be indented to the same level as THEN-clause?
I have this in my .emacs file, yet neither GNU Emacs nor XEmacs indent
it that way.

Regards,
rk

Alain Picard

unread,
Aug 28, 2001, 5:49:31 AM8/28/01
to
John Foderaro <j...@xspammerx.franz.com> writes:

> If you don't understand why it's not because I haven't tried repeatedly to
> explain why. I even have a web page explaining it and I'm sure you've seen
> references to it in my source code.
>
> http://www.franz.com/~jkf/coding_standards.html

I suspect Jochen understands your "reasons" quite well, but just
disagrees with them. FWIW, the "standards" referred to at the
above url just sound like a codification of personal preferences to me,
with no convincing argument in their favour.

Don't get me wrong, you're ALLOWED to have personal preferences! But
so is Jochen.

And to fess up, I too like (well, okay, let's say "don't abhor") LOOP
and dislike IF*.

I think Lisp is really lucky to be so clear as to need so few of
these "coding standards". Anyone of you guys read the Ellemtel C++
coding standards? shudder...

--
It would be difficult to construe Larry Wall, in article
this as a feature. <1995May29....@netlabs.com>

Kent M Pitman

unread,
Aug 28, 2001, 6:15:55 AM8/28/01
to
rich...@gmx.net (Richard Krush) writes:

GNU Emacs 19.34.1 normally indents
(IF X
Y
Z)
but with the above patch does
(IF X
Y
Z)

Perhaps a later Emacs version broke this OR perhaps you've loaded other
indent information you aren't aware of?

Eduardo Muñoz

unread,
Aug 28, 2001, 7:26:05 AM8/28/01
to
rich...@gmx.net (Richard Krush) writes:


> I apologize for intruding with off-topic question, but is this supposed
> to make the ELSE-clause be indented to the same level as THEN-clause?


This works for me with Emacs 20.7.1 and has the
advantage of not messin with emacs-lisp
indentation.

(defun my-common-lisp ()
(set (make-local-variable 'lisp-indent-function)
'common-lisp-indent-function))

(add-hook 'lisp-mode-hook 'my-common-lisp)


HTH and excuse my english :)

--

Eduardo Muñoz

Fred Gilham

unread,
Aug 28, 2001, 10:28:09 AM8/28/01
to

Geoff Summerhayes wrote:

> I can't resist going from the sublime to the ridiculous. After
> visiting the 99 bottles page I noticed they had a program for CL and
> one for CLOS but none that really exercised format. So I rolled up
> my newbie sleeves and came up with this (and as a bonus, it even
> uses loop):
>
> (defun bottle-song (x &optional (stream t))
> (format stream "~{~&~[~^~:;~:*~@(~R~) bottle~:*~P of ~
> beer on the wall~:*~[.~:;,~%~:*~@(~R~) bottle~:*~P ~
> of beer.~%You take one down, pass it around,~%~
> ~[No~:;~:*~@(~R~)~] bottle~:*~P of beer on the ~
> wall.~%~%~:*~]~]~}"
> (loop for i from x downto 0 collect i)))
>
> (bottle-song 99)


This is a masterpiece! Now if only you could put it into the shape of
a beer bottle or a harp or something, you could enter it in an
obfuscated code contest with the best of them!

--
Fred Gilham gil...@csl.sri.com
I was storing data in every conceivable way, including keeping a chain
of sound waves running between the speaker and the microphone. There
was no more memory left to be had....

Marco Antoniotti

unread,
Aug 28, 2001, 10:30:31 AM8/28/01
to

Fred Gilham <gil...@snapdragon.csl.sri.com> writes:

> Geoff Summerhayes wrote:
>
> > I can't resist going from the sublime to the ridiculous. After
> > visiting the 99 bottles page I noticed they had a program for CL and
> > one for CLOS but none that really exercised format. So I rolled up
> > my newbie sleeves and came up with this (and as a bonus, it even
> > uses loop):
> >
> > (defun bottle-song (x &optional (stream t))
> > (format stream "~{~&~[~^~:;~:*~@(~R~) bottle~:*~P of ~
> > beer on the wall~:*~[.~:;,~%~:*~@(~R~) bottle~:*~P ~
> > of beer.~%You take one down, pass it around,~%~
> > ~[No~:;~:*~@(~R~)~] bottle~:*~P of beer on the ~
> > wall.~%~%~:*~]~]~}"
> > (loop for i from x downto 0 collect i)))
> >
> > (bottle-song 99)
>
>
> This is a masterpiece! Now if only you could put it into the shape of
> a beer bottle or a harp or something, you could enter it in an
> obfuscated code contest with the best of them!

No way! Geoff should WRITE a FUNCTION that would reshape the code as
a Bottle of beer. :)

Hallvard B Furuseth

unread,
Aug 28, 2001, 11:33:07 AM8/28/01
to
John, I know it's a religious issue and I'm not saying "now you
should start using loop*", but I'm curious how much this would
take away of your dislike for the thing:

John Foderaro <j...@unspamx.franz.com> writes:

> (...) The Lisp expert however sees in those parens the structure of the
> code. (...)
> The loop macro ruins this. You have an opening paren and a closing


> parens and then a collection of english words with stuff in between.
> There is no longer any structure visible.

That's easy enough to fix when you like wrappers like if* anyway:

(defmacro loop* (&body body)
"LOOP variant which unpacks top-level lists that start with a :keyword.
Example: (loop* (:for x (:in '(:foo bar)) (:collect) x))
becomes (loop :for x :in '(:foo bar) :collect x )"
(cons 'loop (loop :while body
:do (if (and (consp (car body))
(keywordp (caar body)))
(setq body (append (car body) (cdr body))))
:collect (pop body))))

Now you can group and indent loops as much as you like.

> Everyone who've I've seen attracted to the loop macro starts out
> swearing that they will only use it for simple loops but soon get loop
> fever and it's a challenge to them to write the most obscure
> unreadable loop macros they can, using every single loop macro
> keyword.

Hmm. Is that "loop fever" warning advice to others, who'll probably
form their own opinions anyway, or is it also advice to yourself? If
the latter, don't you trust yourself not to do the same if you ever do
start down the evil loop path?

Anyway, do you have any clear idea about which combinations are bad, so
you could add syntax checks to prevent them in loop*? And maybe checks
to forbid silly things like `(:collect) i'. No "redundant" keywords
should be removed though, then you'd need to learn _two_ loop syntaxes.
(Again, I'm not asking you to actually do it. Just wondering if such a
solution could satisfy you.)

--
Hallvard

Erik Naggum

unread,
Aug 28, 2001, 12:02:20 PM8/28/01
to
* John Foderaro

> If you don't understand why it's not because I haven't tried repeatedly
> to explain why. I even have a web page explaining it and I'm sure
> you've seen references to it in my source code.
>
> http://www.franz.com/~jkf/coding_standards.html

There is only one document on Lisp on the whole of the World Wide Web
that makes me _not_ want to use Common Lisp. I think that document says
much more about the religious fervor and irrationality of a supposed
"personal taste" which shows disregard and disrespect for every other
Common Lisp programmer on the planet than any concern for good code. I
happen to *like* Common Lisp just the way it is, damnit!, and both the
language and the tone and the wider implications of the statements in
this file are insults to everyone who has ever thought Common Lisp was a
great language. This file is like a "personal statement" on why women
should have breast implants and other cosmetic surgery, because, frankly,
they are _all_ butt ugly as a matter of course ("one can go on and on
about how bad natural breasts are, but we'll try to be brief") unless
_modified_ to fit the "personal taste" of particular misogynic. Repeat
the experiment of reading this document as if it were about something you
happen to _like_. Do you want to deal with a person who goes out of his
way to insult something _great_ and who thinks marring it is necessary?

But it gets worse, much worse. The exact same kind of religious fervor
and irrationality applies to several other areas. I could deal with the
IF* abomination and the exaggerated hatred for LOOP for a long time,
until I saw that the same thing happen to case in the reader. It is not
that there is a difference in taste, it was that _disresepct_ for those
who held other opinions, the _dishonesty_ of the arguments that there was
only to do this and that and not to worry about a thing, which any smart
Common Lisp programmers would know to be false, and finally, we saw that
reckless abandon that it was the _caller's_ fault if he had failed to
bind *print-upcase* back to the only value it apparently should have
around a call to a low-level function, because *print-upcase* and the
whole case stuff is somehow _wrong_ and thus removed from the language
that has been subject to cosmetic surgery. So this disrespect for Common
Lisp boils down to a pretense that Common Lisp is something it is not.

I have no idea what programming language these "coding standards" really
apply to, but it is not the Common Lisp I would like to use, and I can no
longer trust the purported Common Lisp code that whoever adheres to these
"coding standards" write because I have no idea how many other areas have
been subject to this looney programmer's "personal taste".

Until Sam Steingold got on the CLISP team and apparantly caused it to
move towards ANSI compliance, I had the same kind of distrust in Bruno
Haible's massively arrogant attitude problems towards the standard. I
want to program in Common Lisp, to use the available resources to see
what Common Lisp programs _should_ do (that is what conformance is about
-- screw portability of code -- it is portability of _knowledge_ I care
about), but here this punk goes out of his way to break with the standard
in areas that make absolutely no sense, also denouncing the language as
misdesigned and broken. Why could he not make his modifications as small
_additions_ to the standard? Something _optional_? A case for _choice_?
Why make it so _personal_?

* Alain Picard <api...@optushome.com.au>


> FWIW, the "standards" referred to at the above url just sound like a
> codification of personal preferences to me, with no convincing argument
> in their favour.

Oh, I think it reads like very convincing arguments in their favor,
provided that you are willing to share the arrogance of a person who is
pretending that Common Lisp is not a defined standard, but just a matter
of personal taste and dislikes. If you assume up front that the people
who wrote the standard and agreed on everything in a political process
are idiots who should be kicked in the ass, of course you listen to such
swaying arguments as calling if, when and unless "bogus-tree-conditional".

> Don't get me wrong, you're ALLOWED to have personal preferences! But
> so is Jochen.

You know, I do not think this is a personal preference. It is an attempt
to be a _professional_ preference. Everybody is entitled to their
_personal_ opinions, but for those of us who think _professionalism_ in
dealing with _professional_ issues is a major mark of quality in any
_professional_ programmer, personal opinions are set aside in favor of
making things work together and abiding by professional agreements.

That "coding standard" document is one of the most _unprofessional_
statements of an opinion I can think of right now. It has tainted my
previously good impression of John Foderaro's _professional_ conduct and
it makes him look like a crackpot unaware that he is a crackpot in his
profession, as well. When I work with people, I do not want to _have_ to
care what their personal issues are. I may want to for personal reasons,
but not for professional reasons. It is our _work_ that matters in the
end, and as professional programmers, that means we set aside personal
preferences that get in the way of good professional conduct. Inventing
a stupid new macro with keywords while you denounce the grammer of some
other macros with keywords because of them, only because you don't like
cond and progn and default indentation rules would have been OK if you
confined it to your personal projects, but to _publish_ it? That is like
insisting on an alternative spelling of some words you think look silly
in published literature. Certain authors get away with this because they
sell their _words_, such as poets. But when you do not sell your words,
you sell the information they are trying to convey to a general public,
you abide by community standards and spell them the standard way. If you
do not, you are telling people that you do not care what information you
are selling, you are really in the business of selling your new words.

This is why I urge Franz Inc to remove IF* from their published code. If
you are in the business of selling Common Lisp products, just follow the
standard. If you are the business of selling IF*, proceed as you have.
If John Foderaro makes it as abundently clear as I get the impression he
does that he would never write cond and progn, much less if, when, and
unless in production code, have somebody else (preferably some software)
convert his _personal_ style into _professional_ style for publication.
(This is in fact something several publishing houses do for their wacky
authors, who amazingly accept that they can blame the publisher for the
lack of artistic integrity that is required by the process of publication
and the filthy requirements of money and all that artistic crap you can
get away with as a celebrated author. However, I fail to see how bloody
"artistic" IF* can be that it would mandate a similar acceptance of an
author's attitude problems.)

IF* and its disturbed origin has become a blemish on the community. Any
community can and must deal with weird people, because that is just what
life is like, but when it becomes a weird _profession_ because some are
unwilling to put on a suit and tie when it is _required_ of them, the
whole community suffers. Common Lisp is already considered weird by
some, and the personal conduct of some Lispers does not help, but we
really do not need to deal with irrational _professional_ conduct.

> I think Lisp is really lucky to be so clear as to need so few of these
> "coding standards".

Well said.

///

Coby Beck

unread,
Aug 28, 2001, 12:47:45 PM8/28/01
to

"Erik Naggum" <er...@naggum.net> wrote in message
news:32080033...@naggum.net...

> * John Foderaro
> > If you don't understand why it's not because I haven't tried repeatedly
> > to explain why. I even have a web page explaining it and I'm sure
> > you've seen references to it in my source code.
> >
> > http://www.franz.com/~jkf/coding_standards.html
>
> I think that document says
> much more about the religious fervor and irrationality of a supposed
> "personal taste" which shows disregard and disrespect for every other
> Common Lisp programmer on the planet than any concern for good code.

Erik is right, it is so NOT about good coding practice I'm embarassed for
its author. It is only about if*, loop and an irrelevant personal dislike
of cond, when, if and unless. The tack-on, intelligence-insulting point 3
("oh yeah, use comments") is transparent and woefully inadequate as an
attempt to justify the document's title.

John Foderaro you are not living up to the responsibilities that come with
your role in the lisp community. You are not just another lisp user, free
to do as you please with no obligation to anyone.


> happen to *like* Common Lisp just the way it is, damnit!, and both the
> language and the tone and the wider implications of the statements in

[snip a very long, very harsh tongue-lashing, but lord help me, I can't
disagree with a word!]

> misdesigned and broken. Why could he not make his modifications as
small
> _additions_ to the standard? Something _optional_? A case for
_choice_?
> Why make it so _personal_?
>
> * Alain Picard <api...@optushome.com.au>

> > Don't get me wrong, you're ALLOWED to have personal preferences! But
> > so is Jochen.

But disguising them as "good coding standards" is very disingenuous.


>
[snip -see above-]
>

Coby
--
(remove #\space "coby . beck @ opentechgroup . com")


Friedrich Dominicus

unread,
Aug 28, 2001, 1:16:52 PM8/28/01
to
Erik Naggum <er...@naggum.net> writes:

> * John Foderaro
> > If you don't understand why it's not because I haven't tried repeatedly
> > to explain why. I even have a web page explaining it and I'm sure
> > you've seen references to it in my source code.
> >
> > http://www.franz.com/~jkf/coding_standards.html
>
> There is only one document on Lisp on the whole of the World Wide Web
> that makes me _not_ want to use Common Lisp. I think that document says
> much more about the religious fervor and irrationality of a supposed
> "personal taste" which shows disregard and disrespect for every other
> Common Lisp programmer on the planet than any concern for good
> code.

Well I have to agree to what Eric says.
Following especially point 1 of the list is the road to "Lisp
whatever", 2 is one extreme opionoin about loop. But within the
Standard, 3 is the only I could agree with. Although writing "If it
isn't obvious what a function does, make a note of it", is not a good
idea. Better rewrite it that it is obvious what it does.. Well a bit
too much nit-picking I guess.

Now do we have a Standard or not? If all could agree on introducint an
if* well that's fine. But so long point one make all progams adhering
to it a new Lisp Dialect but definitly not Ansi Common Lisp.

Regards
Friedrich

John Foderaro

unread,
Aug 28, 2001, 1:35:23 PM8/28/01
to
Thanks for the wonderful posting. I have never laughed so hard at a newsgroup
posting. There are so many gems in your posting that it's hard to pick out the
best, but if I had to I'd say that it was the part where you say that you give
me (and I presume the rest of the world) permission to think however we want
however it is absolutely forbidden to *publish* thoughts contrary to what Erik
Naggum thinks. That is so rich!!
(I sure hope that posting this letter isn't considered publishing my thoughts
or I'm in for a 500 line laugh filled response).

Thanks for brightening my day.

Thomas F. Burdick

unread,
Aug 28, 2001, 1:55:12 PM8/28/01
to
Kent M Pitman <pit...@world.std.com> writes:

> rich...@gmx.net (Richard Krush) writes:
>
> > On 26 Aug 2001 15:56:51 -0700, Thomas F. Burdick wrote:
> >
> > > Try adding this to your .emacs file, see how you like it:
> > >
> > > (add-hook 'lisp-mode-hook
> > > #'(lambda ()
> > > (setq lisp-indent-function
> > > 'common-lisp-indent-function)))
> >
> > I apologize for intruding with off-topic question, but is this supposed
> > to make the ELSE-clause be indented to the same level as THEN-clause?
> > I have this in my .emacs file, yet neither GNU Emacs nor XEmacs indent
> > it that way.

Did you evaluate the above form (either with M-C-x, or by restarting),
then open a lisp file in a new buffer? If not, nothing will have
changed yet. You can do
M-: (setq lisp-indent-function 'common-lisp-indent-function) RET
in one buffer to just test it out. If you have any more problems with
it, you should probably post to one of the emacs groups
(gnu.emacs.help, for example).

> GNU Emacs 19.34.1 normally indents
> (IF X
> Y
> Z)
> but with the above patch does
> (IF X
> Y
> Z)

And generally makes it know about CL better. It will generally indent
with-... forms correctly, too.

Kent M Pitman

unread,
Aug 28, 2001, 1:54:34 PM8/28/01
to
Fred Gilham <gil...@snapdragon.csl.sri.com> writes:

> Geoff Summerhayes wrote:
>
> > I can't resist going from the sublime to the ridiculous. After
> > visiting the 99 bottles page I noticed they had a program for CL and
> > one for CLOS but none that really exercised format. So I rolled up
> > my newbie sleeves and came up with this (and as a bonus, it even
> > uses loop):
> >
> > (defun bottle-song (x &optional (stream t))
> > (format stream "~{~&~[~^~:;~:*~@(~R~) bottle~:*~P of ~
> > beer on the wall~:*~[.~:;,~%~:*~@(~R~) bottle~:*~P ~
> > of beer.~%You take one down, pass it around,~%~
> > ~[No~:;~:*~@(~R~)~] bottle~:*~P of beer on the ~
> > wall.~%~%~:*~]~]~}"
> > (loop for i from x downto 0 collect i)))
> >
> > (bottle-song 99)
>
>
> This is a masterpiece! Now if only you could put it into the shape of
> a beer bottle or a harp or something, you could enter it in an
> obfuscated code contest with the best of them!

Heh. I agree. Quite the cute piece by Geoff, and a good suggestion by
Fred to boot. Here's my "contribution"...

- - - - - 8< - - - - - Cut here - - - - - 8< - - - - -

(in-package "CL-USER")

(defun bottle-song (&optional (in-stock 99) (stream *standard-output*))

;; Original idea and primary coding by Geoff Summerhayes
;; <sNuOmS...@hNoOtSmPaAiMl.com>
;; Formatting idea by Fred Gilham <gil...@snapdragon.csl.sri.com>
;; Actual formatting & minor recoding by Kent M Pitman
;; <pit...@world.std.com>

(format

stream
"-----~2%~
~{~&~1&~
~[~^~:;~
~1:*~@(~
~R~) bo~
ttle~:P o~
f beer on t~
he wall~01:*~[.~
~:;,~%~1:*~@(~R~
~) bottle~:*~P ~
of beer.~%You t~
ake one down, p~
ass it around, ~
~01%~[*No* more~
~:;~:01*~@(~R~)~
~] bottle~:*~P ~


of beer on the ~

wall.~2&-----~%~
~1%~:*~]~]~}~0%"

(loop for bottle from in-stock downto 0 collect bottle)))


(bottle-song)

Geoff Summerhayes

unread,
Aug 28, 2001, 2:44:16 PM8/28/01
to

"Kent M Pitman" <pit...@world.std.com> wrote in message
news:sfwd75g...@world.std.com...

> Fred Gilham <gil...@snapdragon.csl.sri.com> writes:
>
> >
> > This is a masterpiece! Now if only you could put it into the shape
of
> > a beer bottle or a harp or something, you could enter it in an
> > obfuscated code contest with the best of them!
>
> Heh. I agree. Quite the cute piece by Geoff, and a good suggestion
by
> Fred to boot. Here's my "contribution"...
>

<blush> High praise, thank you all.

For me, this qualifies as a good reason to celebrate.
Anyone else getting thirsty? <g>

Cheers,
Geoff


John Foderaro

unread,
Aug 28, 2001, 2:55:11 PM8/28/01
to
You guys make it sounds like the ANSI CL standard was handed down by God and it
dare not be criticized.

It's not only our right to criticize it it's our *responsibility*. The
language will never get better if we don't.

I've written a lot of lisp code and I've read and debugged a lot of lisp code
written by others. I have the right and responsibility to codify my experiences
with the hope that others can learn from it. Some are so blinded by faith that
they believe that everything in the CL spec is divine. The fact is that it was
designed by committee. It was a compromise. Not everything in it is a great
idea, or even a good idea.

The sad thing is that the religious zealots seem to have taken over this
newsgroup (or at least they are the loudest). I laugh at them and I hope you
do too. I hope that I can get a message through to the scientists out there who
understand that CL is just a language with good points and bad points and that
we must figure out how to make CL better and continually relevant to the current
computing world.

-john foderaro
franz inc.

Wade Humeniuk

unread,
Aug 28, 2001, 3:03:46 PM8/28/01
to
I like how you open the stream/cap on the bottle!

Wade

Kent M Pitman

unread,
Aug 28, 2001, 4:09:21 PM8/28/01
to
John Foderaro <j...@xspammerx.franz.com> writes:

> You guys make it sounds like the ANSI CL standard was handed down by
> God and it dare not be criticized.

I didn't see anyone say that.

> It's not only our right to criticize it it's our *responsibility*. The
> language will never get better if we don't.

I don't think anyone disagrees here.

> I've written a lot of lisp code and I've read and debugged a lot of lisp
> code written by others. I have the right and responsibility to codify my
> experiences with the hope that others can learn from it. Some are so
> blinded by faith that they believe that everything in the CL spec is divine.
> The fact is that it was designed by committee. It was a compromise. Not
> everything in it is a great idea, or even a good idea.

Still looking for the point of disagreement. Don't see it yet.

> The sad thing is that the religious zealots seem to have taken over this
> newsgroup (or at least they are the loudest).

I'll assume this refers to me. I wish you'd just name people by name so they
could respond. Responding to vague references always feels weird. Who else
does this refer to? Don't you have a "right and responsibility" to say who
it is you disagree with, both so people can know not to trust them/us and
so they can fairly know they are being commented on and defend themselves?

> I laugh at them and I hope you do too. I hope that I can get a message
> through to the scientists out there who understand that CL is just a
> language with good points and bad points and that we must figure out how
> to make CL better and continually relevant to the current computing world.

No problem here per se.

I think the only thing people are disagreeing with you on are whether
labeling a few isolated comments a "coding style" is fair. It would be
as if I wrote a book called "Good Form in Woodworking" and it contained
only the text: "Don't forget to sand the wood when you're done. I hate
splinters." People critiquing my "good form" book would not be meaning
"I like splinters." They would be meaning "There is more to the aesthetic
of woodworking than this and you've omitted so much as to make the title
meaningless." It might suffice to call my masterwork "One Thing To Remember
When Building Things Out of Wood", but even then, people would start to
resent the sheer number of book-covers in my collected works "Encycloopedia",
which they would imagine later including another "book" called "Oh, I forgot,
sometimes it's helpful to dust these things once in a while" (with
contained content that is a substring of the title), and "It helps to have
tools like knives or saws to cut the wood".

One reason I like attending talks on topics, even topics I don't understand
is to acquire "lists". Indeed, it's one way I judge the usefulness of a
speaker on a topic I don't understand is whether they provide me with any
kind of exhaustive partition of the space they are talking about, because
such partitions help me to understand the space of what is and is not being
talked about. A talk about "Some art is ugly." is vague and hard to put
into context. But a talk that takes a position like "Art must be either
beautiful, political, or expensive." gives me a way to evaluate the statement
it's making plus, if I buy into the statement, a way to carve out
subproblems in understanding the space.

If people are reacting to anything, it is perhaps that they've bought into
my claim that all style is about trade-off and that you can't make good
style trade-offs unless you understand the things that are being gained and
the things being lost. What's funny is that almost by definition in this
theory, there are no absolutes. I'm not advocating anyone simply believe
me all the time, nor am I advocating people ignore you all the time. The
funny thing is that you refer to "religious zealots" and people being
"blinded by faith", yet you yourself are the one who is offering up style
rules like "Never use the extended loop macro." that admit no variance.
Your own argument for this position says:

| People who use loop always say, "I just use it for small things."
| But once started down this path they can't help but use it in more
| and more complex ways until they take joy in writing code that
| cannot be deciphered.

which seems to imply that there might be acceptable uses but that you don't
want to be flexible enough to allow those uses for fear of the bad uses,
and so you'd rather also disallow even the acceptable uses. I find that
pretty uncompelling to the point of patronizing.

- - - -

By the way, also, in your point #1 you where you talk about why IF, WHEN,
and UNLESS are bad, you say:

| No other language includes an inverse conditional

You, of course, leave out the natural languages. Yes, it's true, they
aren't programming languages. However, they ARE natural, and
therefore I think prima facie evidence that it is natural to speak in
these terms. If anything, one might say, all other programming
languages besides Lisp are unnatural in this sense.

English has a single word devoted to "unless". The romance languages
typically use a construction like the Spanish "a menos que", but it does
not make appeal to negated-if. I've seen research that says that people
think of inverted conditionals more "efficiently" than negated conditionals
because they think of unless not as


consequent
/
test --- [ negate ] ---- branch

\
alternative


but rather as

alternative
/
test --- branch
\
consequent


getting exactly the speed gain that machine language does when you complement
a conditional; no increased execution time. The stuff I recall seeing (sorry,
I don't have a cite but would be willing to try to track it down if pressed)
also mentioned that it takes less short-term memory to mentally parse
statements with UNLESS because they don't add to the pile of "chunks" being
assembled, and that people can understand and competently manipulate negations
to deeper depth when UNLESS is involved than when WHEN/NOT is involved because
"Unless I'm not here, you can go out to play." doesn't feel as doubly-negative
as "When I'm not not here, you can go out to play."

This omits also discussion of the value of establishing and promoting focus
in discussion, which is why you'd want to choose between "When I'm here"
and "Unless I'm not here" ... these each have subtly different kinds of
emphasis which may be important to the speaker and are often lost in
programming languages.


Dorai Sitaram

unread,
Aug 28, 2001, 4:56:35 PM8/28/01
to

I am probably not alone in feeling awkward about using
IF* because it's not "core", but I must grant that it
seems like it would make maintaining and editing
existing code easier. As things are now, if I modify a
conditional by adding another branch or adding _to_ an
existing branch, I may typically be also required to
make changes that go beyond that simple change: such as
reworking a WHEN or UNLESS into an IF or COND or vice
versa, a WHEN into an UNLESS or vice versa, an IF into
a COND or vice versa, or adding or deleting a
PROGN. IF* avoids all that.

I agree that natural language profits from having a
variety of conditionals and negated conditionals, but
while editing pre-existing code, having to shuffle
keywords in a way not immediately relevant to the
change at hand seems tedious and error-prone. Well, at
least I've been there. I am not sure John
Foderaro highlights _this_ particular point in favor of
IF*.

--d

John Foderaro

unread,
Aug 28, 2001, 5:14:18 PM8/28/01
to
Why do I argue against ideas I don't like rather than make it personal and argue
against specific people? There are a number of reasons. First I feel there's
a lot more content if you stick to ideas rather than hurling childish insults.
Second I don't like the "character assassination by search engine" that goes on
these days where people checking up on you by entering your name find lots of
posts attacking your character. And finally given that news articles are
threaded there is ample context to find the message one is referring to.

In fact in this case I wasn't thinking of you. Are you a CL zealot? Here's a
way to find out. Would you insist that a collection of individuals remove use
of a macro from their published code (even if you may never see that code) just
because that macro isn't an official Common Lisp macro?

This is why I urge Franz Inc to remove IF* from their published code. If
you are in the business of selling Common Lisp products, just follow the
standard.

If you answer yes then you are a zealot.

> I think the only thing people are disagreeing with you on are whether
> labeling a few isolated comments a "coding style" is fair

English is a huge and very complex language. Yet "The Elements of Style" by
Stunk and White is only 105 pages (and they are small pages to boot). No one
has ever put them down for attempting to codify good English style in so small a
book. In fact this is the best known style guide.

I've seen a lot of Lisp code and wrote down the few rules that have the most to
do with making the code readable. I'd always planned on writing more but
nothing has irked me enough to add to the list. It's my right to publish that
and I would urge everyone else to do likewise. Try to codify what you consider
good programming style and practice it.

As for unless. Yes natural languages have it but that does not make it a good
thing for programming languages. You have to mentally insert the 'if not' and
for me that slows down the reading of the program.

Hallvard B Furuseth

unread,
Aug 28, 2001, 5:37:09 PM8/28/01
to
John Foderaro <j...@xspammerx.franz.com> writes:

> Why do I argue against ideas I don't like rather than make it personal

> and argue against specific people? (...)

Good point. Just make it specific enough that we can tell _which_
idea(s) you refer to.

> English is a huge and very complex language. Yet "The Elements of
> Style" by Stunk and White is only 105 pages (and they are small pages
> to boot). No one has ever put them down for attempting to codify good
> English style in so small a book. In fact this is the best known
> style guide.

Fair enough. Note they just call it "style", though. It was your
page's name "coding *standard*" which got to me, in particular since
"standard" has a stronger meaning in programming than in natural
language.

--
Hallvard

Simon András

unread,
Aug 28, 2001, 5:42:40 PM8/28/01
to
Kent M Pitman <pit...@world.std.com> writes:

>
> By the way, also, in your point #1 you where you talk about why IF, WHEN,
> and UNLESS are bad, you say:
>
> | No other language includes an inverse conditional
>
> You, of course, leave out the natural languages. Yes, it's true, they

Not all of them. Hungarian doesn't have 'unless', unless you count
certain hacks that purport to fill this gap. The primary translation
of 'unless' is 'ha nem' ('if not') in the first dictionary I opened.

Not that it affects your argument. :-)

Andras

Hallvard B Furuseth

unread,
Aug 28, 2001, 5:44:57 PM8/28/01
to
[reposting - I lost a paragraph]

John Foderaro <j...@xspammerx.franz.com> writes:

> Why do I argue against ideas I don't like rather than make it personal

> and argue against specific people? (...)

Good point. Just make it specific enough that we can tell _which_
idea(s) you refer to.

> English is a huge and very complex language. Yet "The Elements of


> Style" by Stunk and White is only 105 pages (and they are small pages
> to boot). No one has ever put them down for attempting to codify good
> English style in so small a book. In fact this is the best known
> style guide.

Fair enough. Note they just call it "style", though. It was your


page's name "coding *standard*" which got to me, in particular since
"standard" has a stronger meaning in programming than in natural
language.

Lisp coding standards, not Franz' Lisp coding standards or Foderaro's
Lisp coding standards.

--
Hallvard

Erik Haugan

unread,
Aug 28, 2001, 5:59:59 PM8/28/01
to
* Kent M Pitman -> John Foderaro

> By the way, also, in your point #1 you where you talk about why IF, WHEN,
> and UNLESS are bad, you say:
>
> | No other language includes an inverse conditional
>
> You, of course, leave out the natural languages. Yes, it's true, they
> aren't programming languages. However, they ARE natural, and
> therefore I think prima facie evidence that it is natural to speak in
> these terms. If anything, one might say, all other programming
> languages besides Lisp are unnatural in this sense.

Actually, Perl has unless, for exactly the reason you give, according to the
Camel Book (Programming Perl by Larry Wall et al). I used to program Perl
for a couple of years, and I liked it's tendency to do things in ways
natural to people (and at the same time I learned to hate it's
counterintuitive ways, sloppiness and limitations).

If we look beyond trivialities like "inverse conditionals", a problem is
that people are more likely to believe that "anything goes" in languages
that use more natural (and complex) concepts, so an in depth knowledge isn't
necessary. In general, I've found that more complex languages take longer
to master, but are easier to use when you do.

Erik

Thomas F. Burdick

unread,
Aug 28, 2001, 7:18:11 PM8/28/01
to
Kent M Pitman <pit...@world.std.com> writes:

> By the way, also, in your point #1 you where you talk about why IF, WHEN,
> and UNLESS are bad, you say:
>
> | No other language includes an inverse conditional

Wow, I just went and checked that to make sure it wasn't taken out of
context or misquoted, but it's right alright. It's also absolutely
false. Off the top of my head, Perl has `unless', and SmallTalk has
`ifFalse:'. Of course various assembly languages have JN* (Jump if
Not Zero, etc), which is similar.

Erik Naggum

unread,
Aug 28, 2001, 7:44:36 PM8/28/01
to
* John Foderaro <j...@xspammerx.franz.com>

> You guys make it sounds like the ANSI CL standard was handed down by God
> and it dare not be criticized.

Like most criminals who suddenly get this great political insight into
the law-making process when they get caught, you, too, confuse breaking
community standards with criticizing them. If you had criticized them
while upholding them, you would have gained respect and people would have
listened to you, because it would have meant that you would have followed
the _changing_ consensus and would be interested in helping build it.
Instead, you have a criminal mind, are a loose cannon and a person who
decides on his own when to uphold the laws and when to break them. This
is what a society of laws cannot tolerate in its citizens and community
based on a standard cannot tolerate in its members. You, sir, have no
business talking about criticizing any standards, because you obviously
would not follow a _changed_ standard, either, unless, of course, it was
your own, in which case the whole point of a standard is moot.

> It's not only our right to criticize it it's our *responsibility*. The
> language will never get better if we don't.

Most civilized people understand the difference between obeying the laws
while criticizing them and breaking them in a childish expression of
one's inability to articulate sufficiently thoughtful arguments to sway
those of a different mind to rethink their position and reach compromise.

> Some are so blinded by faith that they believe that everything in the CL
> spec is divine.

You should realize that this statement is a very grave insult to your own
intelligence and has absolutely no bearing on what anyone else thinks or
believes, simply because it is such a fucking insane thing to say.

> The fact is that it was designed by committee. It was a compromise. Not
> everything in it is a great idea, or even a good idea.

_Some_ of us prefer to live in a society where people respect each other
for their competence and professionalism despite their differences of
personal opinions and work through their conflicting desires within the
framework of compromise and imposed ritual, simply because we fully
understand what the alternative entails.

These are among the wider implications of your nutty "coding standards",
and people who are way smarter than you figured it out just reading them.

The wider implication of your incredibly stupid disrespect for compromise
is that you fully expect to _remain_ a stranger to the community. You do
not respect the fact that compromise is what makes it possible for lots
of people to work together for a common goal. That means that you do not
share in the common goal. With your disrespect for criticism of your
ways and your repetition of the exact same line of defense as last time
we fought over conformance, you have shown ourself to be an _enemy_ of
the common goal of those who base their work, money, and livelihood on
the standard and the ability of professional engineers to implement it.

I doubt that you will actually get the message, but it is not that you do
something different, it is that you are so hostile to the ways you think
you have improved upon. Case in point: I quit the SGML business when I
could no longer work with that stupid standard. I can rant and rave
freely about its braindamaged design and do any damn thing I please,
_because_ I quit working with SGML. No customers are harmed because of
my st