From: Mark Carroll
Subject: case query
Date: 
Message-ID: <bcp*zlU3n@news.chiark.greenend.org.uk>
Currently I do something of the form,

(case (or x 'is-nil) ... (is-nil ...))

Is there a nicer way to make case able to match nil? I was surprised
to find it refuses, given that (eql nil 'nil) is true.

Hope I'm not asking too much of this sort of thing - it's just easy
to fall into bad style in Lisp through not knowing enough to pick a
good workaround.

If I missed something in the FAQ, a pointer will do!

-- Mark

From: Gareth McCaughan
Subject: Re: case query
Date: 
Message-ID: <86so78wd5g.fsf@g.pet.cam.ac.uk>
Mark Carroll wrote:

> Currently I do something of the form,
> 
> (case (or x 'is-nil) ... (is-nil ...))
> 
> Is there a nicer way to make case able to match nil? I was surprised
> to find it refuses, given that (eql nil 'nil) is true.

  | * (case nil
  |     ((foo) 'bar)
  |     ((nil) 'baz)
  |     (t 'zog))
  | 
  | BAZ

I guess you're forgetting the parens around NIL.

-- 
Gareth McCaughan            Dept. of Pure Mathematics & Math. Statistics,
················@pobox.com  Cambridge University, England.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <0At*mHU3n@news.chiark.greenend.org.uk>
In article <··············@g.pet.cam.ac.uk>,
Gareth McCaughan  <················@pobox.com> wrote:
>Mark Carroll wrote:
>
>> Currently I do something of the form,
>> 
>> (case (or x 'is-nil) ... (is-nil ...))
>> 
>> Is there a nicer way to make case able to match nil? I was surprised
>> to find it refuses, given that (eql nil 'nil) is true.
>
>  | * (case nil
>  |     ((foo) 'bar)
>  |     ((nil) 'baz)
>  |     (t 'zog))
>  | 
>  | BAZ
>
>I guess you're forgetting the parens around NIL.

I'm not sure why you need any - at least in Paul Graham's "ANSI Common
Lisp" the allegation is that if you have (case x (y z)) then z is
evaluated if x is eql to or a member of y. In my case, x and y are
certainly eql - am I using the wrong 'definition', or just
misunderstanding it? (-:

But thanks for providing something that does appear to work
for me!

-- Mark
From: Barry Margolin
Subject: Re: case query
Date: 
Message-ID: <xMOe3.1086$KM3.247768@burlma1-snr2>
In article <·········@news.chiark.greenend.org.uk>,
Mark Carroll  <·····@chiark.greenend.org.uk> wrote:
>In article <··············@g.pet.cam.ac.uk>,
>Gareth McCaughan  <················@pobox.com> wrote:
>>Mark Carroll wrote:
>>
>>> Currently I do something of the form,
>>> 
>>> (case (or x 'is-nil) ... (is-nil ...))
>>> 
>>> Is there a nicer way to make case able to match nil? I was surprised
>>> to find it refuses, given that (eql nil 'nil) is true.
>>
>>  | * (case nil
>>  |     ((foo) 'bar)
>>  |     ((nil) 'baz)
>>  |     (t 'zog))
>>  | 
>>  | BAZ
>>
>>I guess you're forgetting the parens around NIL.
>
>I'm not sure why you need any - at least in Paul Graham's "ANSI Common
>Lisp" the allegation is that if you have (case x (y z)) then z is
>evaluated if x is eql to or a member of y. In my case, x and y are
>certainly eql - am I using the wrong 'definition', or just
>misunderstanding it? (-:

The CLHS says that y is a list designator, and z is evaluated if x is a
member of that list.  The definition of a list designator says: "a non-nil
atom (denoting a singleton list whose element is that non-nil atom) or a
proper list (denoting itself)."  NIL is not a non-nil atom, so it denotes
itself, i.e. the empty list.

And there's even an example in the CLHS that shows both NIL and (NIL) in
the clause list:

 (dolist (k '(1 2 3 :four #\v () t 'other))
    (format t "~S "
       (case k ((1 2) 'clause1)
               (3 'clause2)
               (nil 'no-keys-so-never-seen)
               ((nil) 'nilslot)
               ((:four #\v) 'clause4)
               ((t) 'tslot)
               (otherwise 'others)))) 

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Tim Bradshaw
Subject: Re: case query
Date: 
Message-ID: <ey3so78kvlo.fsf@lostwithiel.tfeb.org>
* Mark Carroll wrote:
> I'm not sure why you need any - at least in Paul Graham's "ANSI Common
> Lisp" the allegation is that if you have (case x (y z)) then z is
> evaluated if x is eql to or a member of y. In my case, x and y are
> certainly eql - am I using the wrong 'definition', or just
> misunderstanding it? (-:

There's a subtlety here.  The keys in a CASE form are `designators for
a list of objects' which are compared against the keyform.  And it
turns out that a `designator for a list' is either a list or a
*non-NIL* atom which designates a singleton list of that atom.  So if
you want to designate NIL you need to say (NIL).

Which is right because otherwise you would have no way of specifying a
clause that can *never* match.  And although that might seem like a
dumb thing to want to do, it could easily arise both in
machine-generated code, and in the case where you want to `comment
out' a clause (the same way one sometimes says (WHEN NIL ...) to
remove some chunk of code while debugging).

--tim
From: Andy Shaw
Subject: Re: case query
Date: 
Message-ID: <5ioghwuvuw.fsf@bridge.transmeta.com>
Gareth McCaughan <················@pobox.com> writes:
> Mark Carroll wrote:
> 
> > Currently I do something of the form,
> > 
> > (case (or x 'is-nil) ... (is-nil ...))
> > 
> > Is there a nicer way to make case able to match nil? I was surprised
> > to find it refuses, given that (eql nil 'nil) is true.
> 
>   | * (case nil
>   |     ((foo) 'bar)
>   |     ((nil) 'baz)
>   |     (t 'zog))
>   | 
>   | BAZ
> 
> I guess you're forgetting the parens around NIL.

He's not forgetting them -- it's just that the case syntax can use
keylists for each clause, or if the keylist is a singleton key, can
simply use the singleton key in place of the keylist.

Most case statements don't actually use keylists -- i.e. most clauses
only have one key, so it's easy to believe that the case syntax does
not allow for keylists if you haven't read the spec carefully, or if
you haven't seen keylists in code.

If the singleton key is nil, however, you must express it as a one
element list containing nil, because otherwise it could be read as the
empty list.

One of the little quirks of Lisp that you learn over the years ...

-Andy
From: Erik Naggum
Subject: Re: case query
Date: 
Message-ID: <3139917376580571@naggum.no>
* Mark Carroll <·····@chiark.greenend.org.uk>
| I was surprised to find it refuses, given that (eql nil 'nil) is true.

  I hope you are aware that (eql nil '()) is true.

| Hope I'm not asking too much of this sort of thing - it's just easy to
| fall into bad style in Lisp through not knowing enough to pick a good
| workaround.

  the nature of NIL is perhaps non-obvious, but it is a symbol, the only
  false value, the empty list, and the end-of-list marker.  in this case,
  you're bitten by the identity of NIL and the empty list of keys, which
  does not match anything.  one might argue that it doesn't make sense to
  write cases with no keys, and therefore, NIL-qua-symbol should be used
  instead of NIL-qua-list, but it is this that would be the special case,
  not that NIL is the empty list.

#:Erik
-- 
@1999-07-22T00:37:33Z -- pi billion seconds since the turn of the century
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <X-d*6LZ3n@news.chiark.greenend.org.uk>
In article <················@naggum.no>, Erik Naggum  <····@naggum.no> wrote:
>* Mark Carroll <·····@chiark.greenend.org.uk>
>| I was surprised to find it refuses, given that (eql nil 'nil) is true.
>
>  I hope you are aware that (eql nil '()) is true.

Yes, but you snipped my excerpt from Paul Graham's book which
suggested that for a case to match it was sufficient for it to be eql
to the thing concerned, _or_ it to be a member of it. (Which now
clearly isn't quite true when it's nil!)

(snip)
>  does not match anything.  one might argue that it doesn't make sense to
>  write cases with no keys, and therefore, NIL-qua-symbol should be used
>  instead of NIL-qua-list, but it is this that would be the special case,
>  not that NIL is the empty list.

I'm not really sure I accept the argument that the current way is obviously
the correct way to do things and that the other way necessitates a special
case - for example, you could have the rule that if the matching-thing is
a symbol, you try to match it with eql, otherwise you use member, and that
works because nil happens to be a symbol. But, I don't feel strongly either
way: I can see that it might be useful to be able to put something that
nothing can match, so the current way is fine with me. (-:

-- Mark
From: Tim Bradshaw
Subject: Re: case query
Date: 
Message-ID: <ey3n1xelk19.fsf@lostwithiel.tfeb.org>
* Mark Carroll wrote:

> I'm not really sure I accept the argument that the current way is obviously
> the correct way to do things and that the other way necessitates a special
> case - for example, you could have the rule that if the matching-thing is
> a symbol, you try to match it with eql, otherwise you use member, and that
> works because nil happens to be a symbol. But, I don't feel strongly either
> way: I can see that it might be useful to be able to put something that
> nothing can match, so the current way is fine with me. (-:

That is not good because you can not write a clause which *never*
matches (or at least, a clause which a compiler can easily prove never
matches, and thus can optimise away), unless you treat nil as such a
clause. Such clauses arise quite often in machine-generated code (or
in mine, anyway!)  Even more, the current way ties in very naturally
with something that is generating clauses by producing a list of keys
which might sometimes turn out to be the empty list -- if a nil key
matched such an empty list you'd need a whole bunch of special cases
along the lines of `whoops, list empty, better use that gensym I made
earlier so I never match'.

--tim
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <Y7e*Di33n@news.chiark.greenend.org.uk>
In article <···············@lostwithiel.tfeb.org>,
Tim Bradshaw  <···@tfeb.org> wrote:
(snip)
>That is not good because you can not write a clause which *never*
>matches (or at least, a clause which a compiler can easily prove never
>matches, and thus can optimise away), unless you treat nil as such a
>clause. Such clauses arise quite often in machine-generated code (or
>in mine, anyway!)  Even more, the current way ties in very naturally
>with something that is generating clauses by producing a list of keys
>which might sometimes turn out to be the empty list -- if a nil key
>matched such an empty list you'd need a whole bunch of special cases
>along the lines of `whoops, list empty, better use that gensym I made
>earlier so I never match'.

OTOH, it ties in rather unnaturally with something that is generating
clauses by producing a key for each instead of a list of keys. You're
bound to have a problem with either one type of code or the other -
that's simply an artifact of nil being both a symbol and a list - you
simply have to choose which you make it awkward for. If you know that
you're only interested in lists and can't easily avoid producing a nil
clause instead of not producing it at all, why can't you just have the
whole first clause always be (nil) and then a subsequent one won't
matter? e.g.

(case nil
      (nil)
      ('a 4)
      (nil 3))

...or is case not defined to work 'in order'? If so, just put:

(and x
     (case x
      .... ))

So, I don't see that it's much of a problem, unless a decent compiler
wouldn't be clever enough to optimise that away? (<grin> Though, if
you're that worried about performance, why write in Lisp? (-:)

I could easily point out situations where the current behaviour makes
code that expects to put symbols instead of lists rather awkward (and
probably slightly slower), too, as it turned out to in mine. But, when
you have a statement which will match both symbols and lists, what can
you do? There's no right answer; you'll always make it awkward for
somebody.

-- Mark
From: Pierre R. Mai
Subject: Re: case query
Date: 
Message-ID: <87so7655jg.fsf@orion.dent.isdn.cs.tu-berlin.de>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> OTOH, it ties in rather unnaturally with something that is generating
> clauses by producing a key for each instead of a list of keys. You're

Then don't do that(TM).  You seem to imply that the situation is
symmetrical, but it really isn't.  You can always wrap single keys
into lists to get the right effect in a simple way (without any loss
of speed or anything like that in any non-brain-dead compiler).

The other way round would involve duplicating code in clauses, or
special-casing nil.  Your suggestion of introducing a spurious nil
case doesn't quite cut it, IMHO, since you might have a valid nil case 
already.

In effect, CASE wants lists of keys.  Consider the possibility of
providing single keys as a short-cut for users (which have to be aware 
of the special-status of nil anyway)...

There are also a number of other areas in CL which take list
designators, which would have to be changed as well.

And just in my personal opinion, treating nil specially (from the
perspective of the implementation) seems non-Lisp-like, since I
consider the list-structure of source code to take precedence over
contents.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <rQo*Pv43n@news.chiark.greenend.org.uk>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
Pierre R. Mai <····@acm.org> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> OTOH, it ties in rather unnaturally with something that is generating
>> clauses by producing a key for each instead of a list of keys. You're
>
>Then don't do that(TM).  You seem to imply that the situation is
>symmetrical, but it really isn't.  You can always wrap single keys
>into lists to get the right effect in a simple way (without any loss
>of speed or anything like that in any non-brain-dead compiler).

Right. It's just slightly annoying to have to do that - I'm not saying
that one way is strongly better or worse than the other - in fact, I'm
saying quite the opposite.

>The other way round would involve duplicating code in clauses, or
>special-casing nil.  Your suggestion of introducing a spurious nil
>case doesn't quite cut it, IMHO, since you might have a valid nil case 
>already.

But... nil doesn't match anything, so why does it matter if there's a
valid nil case? And how does the 'or' involve duplicate code in each
clause? If the evaluation in 'case' is indeed ordered, which I suspect
it is, I'd have hoped the compiler could optimise away redundant
clauses.

>In effect, CASE wants lists of keys.  Consider the possibility of
>providing single keys as a short-cut for users (which have to be aware 
>of the special-status of nil anyway)...

Yes. That possibility is there. It's offered. Users can offer single
keys, not in lists.

>There are also a number of other areas in CL which take list
>designators, which would have to be changed as well.

Why?

>And just in my personal opinion, treating nil specially (from the
>perspective of the implementation) seems non-Lisp-like, since I
>consider the list-structure of source code to take precedence over
>contents.

Yes, but I've already explained why having case work in the way Paul
Hudson's book suggests it does doesn't treat nil any more specially
than it is at the moment.

-- Mark
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwg135srwj.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
> Pierre R. Mai <····@acm.org> wrote:
> >Mark Carroll <·····@chiark.greenend.org.uk> writes:
> >
> >> OTOH, it ties in rather unnaturally with something that is generating
> >> clauses by producing a key for each instead of a list of keys. You're
> >
> >Then don't do that(TM).  You seem to imply that the situation is
> >symmetrical, but it really isn't.  You can always wrap single keys
> >into lists to get the right effect in a simple way (without any loss
> >of speed or anything like that in any non-brain-dead compiler).
> 
> Right. It's just slightly annoying to have to do that - I'm not saying
> that one way is strongly better or worse than the other - in fact, I'm
> saying quite the opposite.

The point is to be able to generate either a set of cases from single keys
as in:

 `(case ,@(mapcar #'(lambda (key exp) `((,key) ,exp)) (the-keys) (the-exps)))

or from lists of keys

 `(case ,@(mapcar #'(lambda (keys exp) `(,keys ,exp)) (the-keys) (the-exps)))

This is naturally correct in the degenerate cases.  If you use a
hypothetical non-CL language semantics of CASE (which I'll call Hcase to
avoid confusion with the real one) in which NIL means a
symbol instead of a list, the same two computations look like:

 ;; This one is trivially simpler than before.  You buy almost nothing.
 `(Hcase ,@(mapcar #'(lambda (key exp) `(,key ,exp)) (the-keys) (the-exps)))

 ;; This one, which you don't appear to care about, is way more complex
 ;; as a penalty for having made the other one uselessly simpler:
 `(Hcase ,@(mapcan #'(lambda (keys exp)
                      ;; Sigh.  If there are no keys, don't output the clause
                      ;; so it doesn't get confused with symbol NIL
                      (when keys (list `(,keys ,exp))))
		   (the-keys) (the-exps)))

and even then the longer one isn't quite right because when you omit
code [as the above macro does] the compiler doesn't see it and you get
unused variable warnings for the omitted code. You actually want to insert
the code and make it unreachable to avoid the compiler thinking you forgot
about it.  So it works better to do:

 `(Hcase ,@(mapcar #'(lambda (keys exp)
                       ;; !!! KLUDGE Alert: a null list of keys 
                       ;;     will be interpreted wrong, so substitute 
                       ;;     a non-findable token.
                       `(,(or keys (gensym)) ,exp))
                   (the-keys) (the-exps)))

If the semantics of CASE confuses you, the right thing is always to 
use parens around keys.  The other syntax is provided as a shorthand
for people who purport to know what they are doing.  The language could
do without the short form, but not without the long form, in that the 
long form subsumes the short but not vice versa.  As such, hairing
up the short form in a way that makes the long form irregular is a
Bad Idea (TM).  The long form, by rights, must dominate.  And it does.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <nIs*1143n@news.chiark.greenend.org.uk>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
(snip)
>The point is to be able to generate either a set of cases from single keys
>as in:
>
> `(case ,@(mapcar #'(lambda (key exp) `((,key) ,exp)) (the-keys) (the-exps)))
>
>or from lists of keys
>
> `(case ,@(mapcar #'(lambda (keys exp) `(,keys ,exp)) (the-keys) (the-exps)))

Right; thanks for the interesting definitions. (-:

>This is naturally correct in the degenerate cases.  If you use a
>hypothetical non-CL language semantics of CASE (which I'll call Hcase to
>avoid confusion with the real one) in which NIL means a
>symbol instead of a list, the same two computations look like:
>
> ;; This one is trivially simpler than before.  You buy almost nothing.
> `(Hcase ,@(mapcar #'(lambda (key exp) `(,key ,exp)) (the-keys) (the-exps)))

Well, you get not to use an extra cons cell for each clause; though
hopefully in most cases this can be optimised away.

> ;; This one, which you don't appear to care about, is way more complex
> ;; as a penalty for having made the other one uselessly simpler:
> `(Hcase ,@(mapcan #'(lambda (keys exp)
>                      ;; Sigh.  If there are no keys, don't output the clause
>                      ;; so it doesn't get confused with symbol NIL
>                      (when keys (list `(,keys ,exp))))
>		   (the-keys) (the-exps)))
>
>and even then the longer one isn't quite right because when you omit
>code [as the above macro does] the compiler doesn't see it and you get
>unused variable warnings for the omitted code. You actually want to insert

It's not actually particularly more long or complex - you just gain
the "when keys (list".

>the code and make it unreachable to avoid the compiler thinking you forgot
>about it.  So it works better to do:
>
> `(Hcase ,@(mapcar #'(lambda (keys exp)
>                       ;; !!! KLUDGE Alert: a null list of keys 
>                       ;;     will be interpreted wrong, so substitute 
>                       ;;     a non-findable token.
>                       `(,(or keys (gensym)) ,exp))
>                   (the-keys) (the-exps)))

...and I'm not sure I'd want to start calling gensym just to avoid
compiler warnings. Compilers warning you about things that you
intended are another matter; if you can't suppress that locally once
you're satisfied it's okay, it's a compiler problem, not a language
problem.

>If the semantics of CASE confuses you, the right thing is always to 
>use parens around keys.  The other syntax is provided as a shorthand
>for people who purport to know what they are doing.  The language could
>do without the short form, but not without the long form, in that the 
>long form subsumes the short but not vice versa.  As such, hairing
>up the short form in a way that makes the long form irregular is a
>Bad Idea (TM).  The long form, by rights, must dominate.  And it does.

I understand case, thanks to previous articles. I also don't
particularly want to have to arrange lots of cons cells I don't need
when I'm matching single cases - unnecessary conses are also a bad
idea - either choice makes things hairier. This is the problem when
you have a case statements that tries to match symbols, and symbols in
lists. I'm not even saying that's a good thing.

Thanks for the interesting code. (-:

-- Mark
From: Pierre R. Mai
Subject: Re: case query
Date: 
Message-ID: <87zp1d4rvc.fsf@orion.dent.isdn.cs.tu-berlin.de>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> > ;; This one is trivially simpler than before.  You buy almost nothing.
> > `(Hcase ,@(mapcar #'(lambda (key exp) `(,key ,exp)) (the-keys) (the-exps)))
> 
> Well, you get not to use an extra cons cell for each clause; though
> hopefully in most cases this can be optimised away.

Why are you worrying about a few cons cells that are only ever
allocated at compile time?  This is probably the worst case of
micro-optimization I've seen in quite a while.  Do you for the same
reason also only ever use very short variable and function names (in
CL or C)?

> It's not actually particularly more long or complex - you just gain
> the "when keys (list".

Which is a whole conditional, i.e. additional program-logic, which you
need to get right everywhere you generate case forms.  You have to
maintain it, too, etc.  This stuff matters, because it uses programmer 
think-time, and is the source of spurious bugs.

> ...and I'm not sure I'd want to start calling gensym just to avoid
> compiler warnings. Compilers warning you about things that you
> intended are another matter; if you can't suppress that locally once
> you're satisfied it's okay, it's a compiler problem, not a language
> problem.

No it's not, because how are you going to communicate to the compiler
what warnings to surpress?  Remember we are talking about code that
is a mixture of human-supplied and computer-generated code.  Neither
the human nor the macro have complete knowledge of the code involved,
and therefore can't supply correct declarations.  So in effect, you
will get spurious warnings at every use of your macro, and the user
will have to check those warnings in every case and manually override
them.  You are quite comfortable generating a lot of unnecessary
_non-trivial_ work, just to save a couple of parens.

> I understand case, thanks to previous articles. I also don't
> particularly want to have to arrange lots of cons cells I don't need
> when I'm matching single cases - unnecessary conses are also a bad
> idea - either choice makes things hairier. This is the problem when

Why are unecessary conses at read/compile-time a bad idea?  You seem
to have a couple of misconceptions about the costs involved in
programming in general...

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <nsy*NB53n@news.chiark.greenend.org.uk>
<sigh> I give up here. I was just making a throwaway remark and
frankly people seem to be making a rather big deal out of rather
little (an occasional extra 'when' isn't _all_ that terrifying). It's
not even a discussion I care about 'winning'; it's as if anything will
be changed, nor did ever I want it to be.

Thanks to those who gave me help with actual Lisp questions, though.

-- Mark
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfw908xjuaj.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> <sigh> I give up here. I was just making a throwaway remark and [...]

The reason people didn't let you get away with it as a throwaway
remark is the same reason as they wouldn't let you get away with
a throwaway remark like "it would be better if you didn't have to
close all your parentheses".  There are reasons and they are explainable.
You seem not to be hearing them, but the fact is that the community
generally agrees and understands this one.  There are similar situations
in the language that are of the form you think this one is, and we
don't fuss as much over them.  But this one is one that's fairly cut
and dried, so there's no point in us all disagreeing over them.

(coerce nil 'string) vs (string nil) is the closest to a similar case.
It comes down to a choice and the choice is seriously messier.

Puns are pricey to have in the language becuase they lead to ambiguity
but they are also a source of great expressional power, so we live
withthem.  People who don't like them should probably seek out Scheme,
which tends to eschew puns, for better or worse.

Virtually any place in CL you see the designator concept used is a 
potential for discussion on this, but the fact is that the designator
rule is fairly efficiently applied in points of ambiguity and to not
apply it in some places would make a big problem because you'd have to
remember where it was used and where not, as happens in the COERCE/STRING
case above and does cause a great deal of pain.

There are reasons for the COERCE/STRING divergence.  COERCE as
described does a lot of "sequence" coercion while STRING does not
address strings.  It would not make sense for STRING to ever return ()
since STRING admits no lists.  By contrast, COERCE is used heavily to
coerce vectors and arrays and lists back and forth, and not having it
treat NIL as a list would be bad.  That doesn't mean a lot of people
don't get confused, though.  It just means there are reasons, and good
ones, for the decisions  made.  It is more important for there to be
decisions and cessation of wimpering than for people to fight forever
over minutia that cannot have a right answer.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <eUE*Ui63n@news.chiark.greenend.org.uk>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> <sigh> I give up here. I was just making a throwaway remark and [...]
>
>The reason people didn't let you get away with it as a throwaway
>remark is the same reason as they wouldn't let you get away with
>a throwaway remark like "it would be better if you didn't have to
>close all your parentheses".  There are reasons and they are explainable.

(I wasn't trying to say that anything was better.)

>You seem not to be hearing them, but the fact is that the community
>generally agrees and understands this one.  There are similar situations
>in the language that are of the form you think this one is, and we
>don't fuss as much over them.  But this one is one that's fairly cut
>and dried, so there's no point in us all disagreeing over them.

That's okay - certainly there were some good reasons provided, and I
hope I was clear in acknowledging those. (You also didn't happen to
catch me on a good day. (-:) I just didn't find _all_ the reasons
convincing, though through questioning them I didn't necessarily
disagree with all the conclusions: perhaps I came across as being more
sceptical than I intended. And, it's a pity I don't have time right
now to go into the debate more, when there are people who are kindly
happy to explain their positions.

(snip)
>Puns are pricey to have in the language becuase they lead to ambiguity
>but they are also a source of great expressional power, so we live
>withthem.  People who don't like them should probably seek out Scheme,
>which tends to eschew puns, for better or worse.

(What are puns? I don't know Scheme - the little I know makes me think
that it doesn't allow symbols to have values _and_ functions - would
it make sense if I said I preferred Standard ML to Lisp for some
reasons?)

(snip interesting coerce discussion)
>ones, for the decisions  made.  It is more important for there to be
>decisions and cessation of wimpering than for people to fight forever
>over minutia that cannot have a right answer.

I wasn't exactly whimpering; I took pains to make it clear that I
didn't have a problem with things-as-they-are. So, I'll just take the
above as a general prescriptive comment. (-:

-- Mark
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwpv296x1v.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> >Puns are pricey to have in the language becuase they lead to ambiguity
> >but they are also a source of great expressional power, so we live
> >withthem.  People who don't like them should probably seek out Scheme,
> >which tends to eschew puns, for better or worse.
> 
> (What are puns? I don't know Scheme - the little I know makes me think
> that it doesn't allow symbols to have values _and_ functions - would
> it make sense if I said I preferred Standard ML to Lisp for some
> reasons?)

Punning, as in natural language, is the use of two unlikely meanings of
a word in the same context for simultaneous communicational effect.

Here are some examples:

 * A symbol has many attributes.  For example, it has an associated
   function cell (and so is funcallable) and it has a property list.
   When you do (mapcar #'car some-list) you are not punning because
   you know that only funcall is used by mapcar.  But suppose in some
   circumstance you have some function FOO that does
     (funcall x (string x))
   If you pass such a function #'car, this won't be good, but if you
   pass it 'car it will work.  That's because FOO is a function that
   puns.  Puns are rarely clean but are often very useful in patching
   or in debugging because they opportunistically exploit the richness
   of a data flow path in a useful way.

 * Once in Macsyma, I cam across the following situation:  A certain
   data structure was used for rational numbers (it arose before they
   were primitive to Lisp and I think persisted and continues to be
   used perhaps now in Macsyma because it was so pervasive):
   (<some-marker> <numerator> <denominator>).  Similarly, there was
   some other representation for polynomials which was something like
   (<some-marker> <sign information> . <other-stuff>).  I remember
   coming across a case where someone had done (minusp (cadr x))
   and to my horror discovering that this was making the assumption
   that the arg was EITHER of these two things and that fortuitously
   they both shared a common property, that the sign of their cadr
   would answer the question they needed to ask.  So rather than do
   (if (foo? x) (minusp (foo-sign x)) (minusp (bar-sign x)))
   where both foo-sign and bar-sign were implemented by cadr, they
   just "punned" and bypassed that.

Puns almost always have that same "groan" attached to them when you
figure it out.  And yet they almost always carry a certain kind of
efficiency of expression that cannot be duplicated in long form. 
Take any pun a comedian tells you and untangle the thing into the
unrelated expression using proper terminology  and it won't be funny
or compact any more.  

IMO, and it's something of an overgeneralization, the Scheme community
which leans closer to the strong-typing end of the universe,
likes precision in its terms and mostly would never stand for puns.  But I
think they are on occasion useful and I don't support the idea of
flushing them.  (That's a pun, by the way; reread the sentence with "they"
meaning either "puns" or "the scheme community".)
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <w1E*A283n@news.chiark.greenend.org.uk>
Thank you very much! An interesting aspect of learning Lisp has been
the vocabulary. (-:

-- Mark
From: Rob Warnock
Subject: Re: case query
Date: 
Message-ID: <7lmnrl$5l9ci@fido.engr.sgi.com>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| Puns are pricey to have in the language becuase they lead to ambiguity
| but they are also a source of great expressional power, so we live
| with them.  People who don't like them should probably seek out Scheme,
| which tends to eschew puns, for better or worse.
+---------------

E.g., Scheme[*] doesn't even *allow* singleton keys in "case" -- the first
element of each clause *must* be a list (except for the "else" clause).


-Rob

[*] By "Scheme" I mean R[45]RS (though  I've run across a few specific
implementations which *do* allow it)...

-----
Rob Warnock, 8L-855		····@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		FAX: 650-933-0511
Mountain View, CA  94043	PP-ASEL-IA
From: Vassil Nikolov
Subject: Re: case query
Date: 
Message-ID: <l03130301b3a426ca6adf@195.138.129.103>
On 1999-07-03 19:51 +0100,
Mark Carroll wrote:

  > <sigh> I give up here. I was just making a throwaway remark and
  > frankly people seem to be making a rather big deal out of rather
  > little (an occasional extra 'when' isn't _all_ that terrifying). It's
  > not even a discussion I care about 'winning'; it's as if anything will
  > be changed, nor did ever I want it to be.
  [...]

It is a big deal because:

(1) there are other people reading this thread, including learners of
    Lisp, and they should get things right;

(2) this issue, perhaps small by itself, is one of the tips of bigger
    and important issues concerning language design.

People spend their time writing all those posts because they _care_
about getting _things_ right, not because they want to demonstrate
that a particular _person_ has made a mistake.

Sorry for wasting bandwidth^1 for obvious things.
__________
^1 I mean human cognitive bandwidth, of course, not that of
   telecommunications channels


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwlncxoe5b.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> > ;; This one is trivially simpler than before.  You buy almost nothing.
> > `(Hcase ,@(mapcar #'(lambda (key exp) `(,key ,exp)) (the-keys) (the-exps)))
> 
> Well, you get not to use an extra cons cell for each clause; though
> hopefully in most cases this can be optimised away.

It is optimized into an EQL check in every implementation I know of.
The extra cons is only there at compile time, and I assure you there
is plenty of other gratuitous consing at compile time for the sake
of macro expansion.  Concern over it is utterly wasted.  Mankind has
larger problems to solve than one little ephemeral compile-time cons
when clarity hangs in the balance.

> It's not actually particularly more long or complex - you just gain
> the "when keys (list".

You missed the MAPCAN.  That's more complex.  And a WHEN is more
complex than no when.  Whether that's materially longer doesn't matter
to me.  It's plainly more irregular when you do it the way you are
trying to claim is arbitrary and equivalent; hence my claim that it is
not arbitrary to have made the other choice.
 
> ...and I'm not sure I'd want to start calling gensym just to avoid
> compiler warnings.

Perhaps because you haven't lived in the day of doing them.
Often I did semantically worse things.  My Maclisp code used to
use the idiom (or keys '($make-compiler-happy$)) which was simpler
to write but technically had a bug in it.

> Compilers warning you about things that you
> intended are another matter; if you can't suppress that locally once
> you're satisfied it's okay, it's a compiler problem, not a language
> problem.

Not if the language provides you no way to say that what you want is
ok.  That cannot be extra-lingual.  Valid code must be possible to get
to compile properly with only linguistic help.  In CL, we warn about
unused variables and we provide ways to case-mark unused variables as
ok not to warn about.  To omit code without having it traversed for
unused variables is to break that chain.  Better to emit dead code.
That happens not to get warned about.  One might argue that dead code
should require a declaration to say (DECLARE (DEAD CODE)) or (DECLARE
(OK IF DEAD CODE)) but we happen not to do that.  If you regard that
as a bug, the bug is in the langauge, not in a compiler. Compilers
implement but do not define the semantics of the language.

> >If the semantics of CASE confuses you, the right thing is always to 
> >use parens around keys.  The other syntax is provided as a shorthand
> >for people who purport to know what they are doing.  The language could
> >do without the short form, but not without the long form, in that the 
> >long form subsumes the short but not vice versa.  As such, hairing
> >up the short form in a way that makes the long form irregular is a
> >Bad Idea (TM).  The long form, by rights, must dominate.  And it does.
> 
> I understand case, thanks to previous articles. I also don't
> particularly want to have to arrange lots of cons cells I don't need
> when I'm matching single cases - unnecessary conses are also a bad
> idea - either choice makes things hairier. This is the problem when
> you have a case statements that tries to match symbols, and symbols in
> lists. I'm not even saying that's a good thing.

If you adopt this attitude, you will be programming at the cons-cell
optimization level for the rest of your natural life and will never
rise to the height of doing anything interesting.  Even if this were
a runtime-cons problem, which it is not, it is only a constant factor.
Constant factors do not stand in the way of you and doing great things
with your life.  What does stand in the way of you and great things
is things that contribute O(n) and if you micro-optimize every aspect
of everything you write without regard to whether it matters, you are 
contributing an O(c) to  to all code you ever write where c is the size
of the code you write.  If you instead optimize only the things that
matter, you will only contribute as an optimizzation phase 
somethign aprpoximating O(1) and you will have a material amount more time
left in your life to do better things.

> Thanks for the interesting code. (-:

Sure.
From: Vassil Nikolov
Subject: Re: case query
Date: 
Message-ID: <l03130300b3a426234397@195.138.129.103>
On 1999-07-03 18:31 +0200,
Pierre R. Mai wrote:

  [...]
  > Why are you worrying about a few cons cells that are only ever
  > allocated at compile time?  This is probably the worst case of
  > micro-optimization I've seen in quite a while.  Do you for the same
  > reason also only ever use very short variable and function names (in
  > CL or C)?
  [...]

I suddenly saw the light: indentation is bad because it wastes storage
for all that redundant white space...


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: Tim Bradshaw
Subject: Re: case query
Date: 
Message-ID: <ey3pv29yeoc.fsf@lostwithiel.tfeb.org>
* Mark Carroll wrote:

> Yes, but I've already explained why having case work in the way Paul
> Hudson's book suggests it does doesn't treat nil any more specially
> than it is at the moment.

You've missed the point that I was trying to make at least.  I
want a way of specifying a clause that can *never* match, completely
regardless of what comes into the case.  I don't think you can do that
without introducing another gratuitous special symbol (say `never')
the way that you suggest.  If NIL matched NIL:

	(case nil
	  (nil (explode-world)))

explodes the world, and I do not believe there is anything I can write
for ? which will cause me to be sure that in this case, where I know
*nothing* about X:

	(case x
	  (? (explode-world)))

the world will not explode: () doesn't work because it is NIL and will
match NIL. A non-NULL list does not work because X could be the same
as one of its members.  I need to introduce something like NEVER:

	(case x
	  (never (explode-world))

or perhaps use a gensym:

	(case x
	  (:#foo (explode-world)))

both of which are, I think, significantly worse than the current
situation (I already do not very much like T and OTHERWISE).

Lest this seem obscure, it's not that uncommon for me, both for
machine generated code and also where I just want to remove a whole
bunch of stuff for testing. I often end up with this kind of thing in
code being debugged:

	(case x
	  (nil (:foo :bar)
	   (do-foo-or-bar x)))

Anyway, I've sad enough on this.

--tim
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <NWx*rx53n@news.chiark.greenend.org.uk>
In article <···············@lostwithiel.tfeb.org>,
Tim Bradshaw  <···@tfeb.org> wrote:
>* Mark Carroll wrote:
>
>> Yes, but I've already explained why having case work in the way Paul
>> Hudson's book suggests it does doesn't treat nil any more specially
>> than it is at the moment.
>
>You've missed the point that I was trying to make at least.  I
>want a way of specifying a clause that can *never* match, completely
>regardless of what comes into the case.  I don't think you can do that
>without introducing another gratuitous special symbol (say `never')
>the way that you suggest.  If NIL matched NIL:

...or use the macro posted elsewhere that makes use of 'when'.

(snip)
>both of which are, I think, significantly worse than the current
>situation (I already do not very much like T and OTHERWISE).

I can understand that. (-:

>Lest this seem obscure, it's not that uncommon for me, both for
>machine generated code and also where I just want to remove a whole
>bunch of stuff for testing. I often end up with this kind of thing in
>code being debugged:
>
>	(case x
>	  (nil (:foo :bar)
>	   (do-foo-or-bar x)))
(snip)

A few semi-colons may do the job admirably, but I do take your
point. (-: I'm not denying that things-as-they-are give rise to
certain conveniences.

-- Mark
From: Tim Bradshaw
Subject: Re: case query
Date: 
Message-ID: <nkjg134v9zb.fsf@tfeb.org>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> Tim Bradshaw  <···@tfeb.org> wrote:

> >both of which are, I think, significantly worse than the current
> >situation (I already do not very much like T and OTHERWISE).
> 
> I can understand that. (-:

But I realise I was wrong about that (I'm two levels back here).  For
the dual of the reasons I want a clause that can never match, I want a
clause that always matches, and that's what T/OTHERWISE do.  I guess
if I was being purist I'd argue for only one of them.  It's slightly
irritiating (to me) that they have to be treated as a special case
inthe syntax, but that doesn't mean I want to see a
clause-that-can-never-match forced to be another special case (which
it is not now).

(All that sounds depressingly languaghe-purist, I guess I should go
and live on comp.lang.scheme now).

> A few semi-colons may do the job admirably, but I do take your
> point. 

They don't really because they result in a huge raft of
unused-variable warnings, and more significantly the code generators I
write generate bits of Lisp not comments, so it's hard to comment out
things (I mean, it's hard to generate commented-out-code).

--tim
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwg134tklk.fsf@world.std.com>
Tim Bradshaw <···@tfeb.org> writes:

> ... I want a
> clause that always matches, and that's what T/OTHERWISE do.  I guess
> if I was being purist I'd argue for only one of them.

That was a compatibility issue. Maclisp CASE had T and LispM SELECTQ
had OTHERWISE, if I recall.  Or if not there were 43 other private
macros of the same ilk that randomly observed one or the other
convention.  It was a real soup of ideas replicated with wide variation,
and only one going forward.  Not unlike the fossil record of animal
species at various times in the past.
From: Tim Bradshaw
Subject: Re: case query
Date: 
Message-ID: <ey3r9mpygmo.fsf@lostwithiel.tfeb.org>
* Mark Carroll wrote:
> (and x
>      (case x
>       .... ))

But that fails because there may be a completely valid NIL clause.  I
want a clause that can never match any key (which CL provides).

--tim
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <54r*tW43n@news.chiark.greenend.org.uk>
In article <···············@lostwithiel.tfeb.org>,
Tim Bradshaw  <···@tfeb.org> wrote:
>* Mark Carroll wrote:
>> (and x
>>      (case x
>>       .... ))
>
>But that fails because there may be a completely valid NIL clause.  I
>want a clause that can never match any key (which CL provides).

Depends if you're expecting a completely valid NIL clause (I'm now
guessing that people mean ((nil) something) by this, rather than (nil
something)). If you are, and can't make sure it's coming first, it
should be beyond your wits to make the (nil something) ones disappear
before the case is evaluated just as it's not beyond mine to make sure
keys appears in a list. Either way, it's really little trouble.

-- Mark
From: Pierre R. Mai
Subject: Re: case query
Date: 
Message-ID: <87908x67q8.fsf@orion.dent.isdn.cs.tu-berlin.de>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> Right. It's just slightly annoying to have to do that - I'm not saying
> that one way is strongly better or worse than the other - in fact, I'm
> saying quite the opposite.

But _WE_ are saying that one way _is_ strongly better than another,
because the situation is not symmetrical, and therefore the decission
to treat nil as it is treated was _not_ arbitrary.

Why are you so worked up over the "special" treatment of NIL in case?
What about the special treatment of T and OTHERWISE?  There are far
less convincing reasons for them to be treated specially, yet they
are, and I've not heard you complain that (case 'x (t 'y)) returns y
although (eql 'x 't) => NIL.

BTW: T and OTHERWISE are the chief reasons (together with NIL) why any
code that expects to automatically generate case forms with singleton
keys is fundamentally broken, unless you can guarantee (which you
usually can't) that NIL, T and OTHERWISE will never be valid keys.

> >The other way round would involve duplicating code in clauses, or
> >special-casing nil.  Your suggestion of introducing a spurious nil
> >case doesn't quite cut it, IMHO, since you might have a valid nil case 
> >already.
> 
> But... nil doesn't match anything, so why does it matter if there's a
> valid nil case? And how does the 'or' involve duplicate code in each

If I may quote part of your previous message:

Mark Carroll <·····@chiark.greenend.org.uk> writes:

> simply have to choose which you make it awkward for. If you know that
> you're only interested in lists and can't easily avoid producing a nil
> clause instead of not producing it at all, why can't you just have the
> whole first clause always be (nil) and then a subsequent one won't
> matter? e.g.
> 
> (case nil
>       (nil)
>       ('a 4)
>       (nil 3))

This approach breaks down the moment you want to produce a clause that
matches nil (the symbol).  In that case you'd have to replace the
first default nil-clause with the clause you would produce.  But you
can't easily do that, because order is important in case.

> clause? If the evaluation in 'case' is indeed ordered, which I suspect
> it is, I'd have hoped the compiler could optimise away redundant
> clauses.

In effect the only reliable way to produce code for your case would
be to only ever produce single keys in clauses.  That would mean the
duplication of body-code for clauses which normally would have had
more than one key with identical bodies.  You would need quite a
clever compiler to recognize "identical" code at this level...

> Yes. That possibility is there. It's offered. Users can offer single
> keys, not in lists.

The emphasis here is on users.  Any piece of code that expects to
automatically generate case forms, but doesn't use lists of keys is
severely brain-damaged.

> >There are also a number of other areas in CL which take list
> >designators, which would have to be changed as well.
> 
> Why?

Because IMNSHO opinion, a language which treated nil in one way everywhere,
except for case, where it suddenly gets treated differently would be really
brain-damaged...  Currently nil is treated uniformly as the empty list
(which it is, i.e. (eq nil '()) => t) whereever a list is a valid value.

> Yes, but I've already explained why having case work in the way Paul
> Hudson's book suggests it does doesn't treat nil any more specially
> than it is at the moment.

I think it's Paul Graham's book you mentioned.  And a beginner's
introduction type of book is seldom the place to look for exact
definitions to guide language design.  Also we've already explained
x-times why having it naively work that way will cause serious
problems with consistency and cause greatly increased complexity in a
wide variety of code.  This usually is a good indication that your
definition runs against the grain of the rest of CL.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <UDx*Pv53n@news.chiark.greenend.org.uk>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
Pierre R. Mai <····@acm.org> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> Right. It's just slightly annoying to have to do that - I'm not saying
>> that one way is strongly better or worse than the other - in fact, I'm
>> saying quite the opposite.
>
>But _WE_ are saying that one way _is_ strongly better than another,
>because the situation is not symmetrical, and therefore the decission
>to treat nil as it is treated was _not_ arbitrary.

Depends on the reasos given though. The only convincing ones I've seen
is the fact that a different case statement would break older code
that expects it to behave in a certain way, and that keylists could be
viewed as a general case and the special-case 'subset' should be
broken in preference to that; both good points IMO.

>Why are you so worked up over the "special" treatment of NIL in case?

I'm not worked up over it; I'm amazed how everyone else seems to be
though. I've made it clear I'm happy with CL as it is.

>What about the special treatment of T and OTHERWISE?  There are far
>less convincing reasons for them to be treated specially, yet they
>are, and I've not heard you complain that (case 'x (t 'y)) returns y
>although (eql 'x 't) => NIL.

Nor am I complaining that (case nil (nil 4)) returns NIL; I'm just
noting in passing there are other ways it could have been done.

>BTW: T and OTHERWISE are the chief reasons (together with NIL) why any
>code that expects to automatically generate case forms with singleton
>keys is fundamentally broken, unless you can guarantee (which you
>usually can't) that NIL, T and OTHERWISE will never be valid keys.

Yes, true, as things are now.

(snip)
>> >case doesn't quite cut it, IMHO, since you might have a valid nil case 
>> >already.
>> 
>> But... nil doesn't match anything, so why does it matter if there's a
>> valid nil case? And how does the 'or' involve duplicate code in each
>
>If I may quote part of your previous message:

Certainly. (-:

>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> simply have to choose which you make it awkward for. If you know that
>> you're only interested in lists and can't easily avoid producing a nil
>> clause instead of not producing it at all, why can't you just have the
>> whole first clause always be (nil) and then a subsequent one won't
>> matter? e.g.
>> 
>> (case nil
>>       (nil)
>>       ('a 4)
>>       (nil 3))
>
>This approach breaks down the moment you want to produce a clause that
>matches nil (the symbol).  In that case you'd have to replace the
>first default nil-clause with the clause you would produce.  But you
>can't easily do that, because order is important in case.

This has popped up in other sub-threads now; I misunderstood what you
meant by 'valid nil case'.

(snip)
>In effect the only reliable way to produce code for your case would
>be to only ever produce single keys in clauses.  That would mean the

Not really - just put it all in lists as you do now, but make sure
that nil list clauses disappear - code to do this has appeared
elsewhere in this thread. I'm not suggesting you get rid of key lists
from case.

>duplication of body-code for clauses which normally would have had
>more than one key with identical bodies.  You would need quite a
>clever compiler to recognize "identical" code at this level...

Modern compilers are indeed quite clever - we've had CSE for many
years, for example. But I'm not suggesting things be done like that.

>> Yes. That possibility is there. It's offered. Users can offer single
>> keys, not in lists.
>
>The emphasis here is on users.  Any piece of code that expects to
>automatically generate case forms, but doesn't use lists of keys is
>severely brain-damaged.

Depends what's known about the keys it'll be generating, no?

>> >There are also a number of other areas in CL which take list
>> >designators, which would have to be changed as well.
>> 
>> Why?
>
>Because IMNSHO opinion, a language which treated nil in one way everywhere,
>except for case, where it suddenly gets treated differently would be really
>brain-damaged...  Currently nil is treated uniformly as the empty list
>(which it is, i.e. (eq nil '()) => t) whereever a list is a valid value.

nil is also uniformly regarded as a regular symbol you can do eq with
and things though, except that 'case' treats it differently when it
appears outside a list in matching it with the symbol supplied. (Or
atom or something? I believe it does eql.) If non-uniform treatment of
nil makes Lisp broken, then frankly it's too late.

(snip)
>I think it's Paul Graham's book you mentioned.  And a beginner's
>introduction type of book is seldom the place to look for exact
>definitions to guide language design.  Also we've already explained

<laugh> It's hardly a beginner's introduction type of book unless
you're already a good programmer (my boss hates people trying to learn
from it because it's too 'dense') - instead, I'd say that Touretzky's
(sp?), etc. was more a beginner's introduction type of book - in fact,
Paul Graham's has a big 'ANSI' on the front and a very meaty reference
section for most of the back which is the only place most special
forms are explained - I think it's reasonable for me to expect decent
definitions from it!

(but apparently not)

Which (in-print) books would you recommend as a desktop reference?

>x-times why having it naively work that way will cause serious
>problems with consistency and cause greatly increased complexity in a
>wide variety of code.  This usually is a good indication that your

I think you're overstating this a little.

>definition runs against the grain of the rest of CL.

To be honest, I think that lumping single keys, keylists,
else-clauses, etc. all together in 'case' in the curious manner that
they are causes enough inconsistency that it runs against the grain of
the rest of CL anyway. 'loop' at it's worst isn't simple enough
either; what I like about Lisp is what I like about UNIX - power
coming from the combination of _simple_ things.

-- Mark
From: Pierre R. Mai
Subject: Re: case query
Date: 
Message-ID: <87lncx47nr.fsf@orion.dent.isdn.cs.tu-berlin.de>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

I give up!  Maybe you'll see the point when you start writing
non-trivial macros generating case, but before that I'm afraid you'll
just discount any non-trivial problem for other people as equally
trivial as your problems.

> (snip)
> >I think it's Paul Graham's book you mentioned.  And a beginner's
> >introduction type of book is seldom the place to look for exact
> >definitions to guide language design.  Also we've already explained
> 
> <laugh> It's hardly a beginner's introduction type of book unless
> you're already a good programmer (my boss hates people trying to learn

It _IS_ a beginner's introduction type of book _about CL_.  I know the
book, I've had people learn CL with this.  I learned Common Lisp from
CLTL.  There are far harder things to learn in programming than CL,
and far harder texts to consume than ANSI Common Lisp (or in fact even
On Lisp).

> from it because it's too 'dense') - instead, I'd say that Touretzky's
> (sp?), etc. was more a beginner's introduction type of book - in fact,
> Paul Graham's has a big 'ANSI' on the front and a very meaty reference
> section for most of the back which is the only place most special
> forms are explained - I think it's reasonable for me to expect decent
> definitions from it!

No it is not.  The only place to expect definitive definitions from
are language standards.  Anything else may have ommissions, bugs,
inaccuracies, etc. (language standards have them, too, but since they
are definitive, that is not a problem <g>).

> Which (in-print) books would you recommend as a desktop reference?

The language standard of course.  And since it's your lucky day, it so 
happens that you don't have to shell out $350 for the hardcopy from
ANSI, but can also obtain a Hypertext version of the same text body
from http://www.harlequin.com/books/HyperSpec

This is where you'll find definitve answers.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <-oF*I583n@news.chiark.greenend.org.uk>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
Pierre R. Mai <····@acm.org> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>I give up!  Maybe you'll see the point when you start writing
>non-trivial macros generating case, but before that I'm afraid you'll
>just discount any non-trivial problem for other people as equally
>trivial as your problems.

Yes; I suspect we can just agree to differ for now, especially given that
what I think will make no real-world difference to anything anyway. (-:

(snip)
>It _IS_ a beginner's introduction type of book _about CL_.  I know the
>book, I've had people learn CL with this.  I learned Common Lisp from

Yes, actually I did. (-: Then again, I learned Perl from "Programming
Perl", not "Learning Perl"; I'd put it at about the same level,
frankly.

>CLTL.  There are far harder things to learn in programming than CL,

Yes.

>and far harder texts to consume than ANSI Common Lisp (or in fact even
>On Lisp).

Yes.

>> from it because it's too 'dense') - instead, I'd say that Touretzky's
>> (sp?), etc. was more a beginner's introduction type of book - in fact,
>> Paul Graham's has a big 'ANSI' on the front and a very meaty reference
>> section for most of the back which is the only place most special
>> forms are explained - I think it's reasonable for me to expect decent
>> definitions from it!
>
>No it is not.  The only place to expect definitive definitions from
>are language standards.  Anything else may have ommissions, bugs,
>inaccuracies, etc. (language standards have them, too, but since they
>are definitive, that is not a problem <g>).

I'm not so sure: other languages manage to have cheap, handy
paperbacks which do a great job of accurately explaining the standard
- e.g. Harbison & Steele's "C: A Reference Manual", Greg Nelson's
"Systems Programming With Modula-3", etc. For one not to be available
for such an important language as ANSI Common Lisp is something I find
kind of surprising. OTOH, perhaps I just happened to be unlucky enough
stumble on one of the handful of slightly inaccuracies in Paul
Graham's book. (-: (I had the same unluckiness with the references
in Schneiers' "Applied Cryptography"...)

>> Which (in-print) books would you recommend as a desktop reference?
>
>The language standard of course.  And since it's your lucky day, it so 
>happens that you don't have to shell out $350 for the hardcopy from

(Heh - cue my rant about how on Earth am I meant to follow standards I
 can't afford to look at? (-:)

>ANSI, but can also obtain a Hypertext version of the same text body
>from http://www.harlequin.com/books/HyperSpec
>
>This is where you'll find definitve answers.

Great! If only someone provided a nicely-commented book form of
it. (-: But, then again, my dislike of solely-electronic documentation
is something I'm increasingly having to get over as fewer and fewer
useful documents are provided in conveniently-printable form.

Thanks again.

-- Mark
From: Vassil Nikolov
Subject: Re: case query
Date: 
Message-ID: <l03130300b3a3906c70c2@195.138.129.121>
On 1999-07-03 09:23 +0100,
Mark Carroll wrote:

  [...]
  > OTOH, it ties in rather unnaturally with something that is generating
  > clauses by producing a key for each instead of a list of keys. You're
  > bound to have a problem with either one type of code or the other -
  > that's simply an artifact of nil being both a symbol and a list - you
  > simply have to choose which you make it awkward for.
  [...]
  > I could easily point out situations where the current behaviour makes
  > code that expects to put symbols instead of lists rather awkward (and
  > probably slightly slower), too, as it turned out to in mine. But, when
  > you have a statement which will match both symbols and lists, what can
  > you do? There's no right answer; you'll always make it awkward for
  > somebody.

The syntax (CASE ... (SYMBOL ...) ...) is no more than shorthand for
(CASE ... ((SYMBOL) ...) ...), sort of syntactic sugar.  There could be
a difference in speed only with interpreted code, but in that case
one doesn't care much about speed.

When generating clauses programmatically, the right approach is
to always wrap up the keys in lists, whether or not there is just
a single key (otherwise one has to specially test for NIL or T or
OTHERWISE which is far more awkward).

Or am I missing something and this is about a completely different
issue?


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <LGo*pu43n@news.chiark.greenend.org.uk>
In article <·····················@195.138.129.121>,
Vassil Nikolov  <········@poboxes.com> wrote:
(snip)
>The syntax (CASE ... (SYMBOL ...) ...) is no more than shorthand for
>(CASE ... ((SYMBOL) ...) ...), sort of syntactic sugar.  There could be
>a difference in speed only with interpreted code, but in that case
>one doesn't care much about speed.

That's okay; I wasn't. I was talking more about the definition.

>When generating clauses programmatically, the right approach is
>to always wrap up the keys in lists, whether or not there is just
>a single key (otherwise one has to specially test for NIL or T or
>OTHERWISE which is far more awkward).

Apparently so; that's just an artifact of how things are, though.

>Or am I missing something and this is about a completely different
>issue?

All I was saying is I dispute the suggestion that the behaviour with
matching nil is obviously 'correct' - you could choose to allow it or
not and it would make different things awkward, depending on what you
were up to - I figure the decision's fairly arbitrary, and that the
(slightly incorrect) definition of 'case' given in Paul Hudson's book
is overall no more or less sensible than the actual CLHS one.

-- Mark
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwemipsrlx.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> All I was saying is I dispute the suggestion that the behaviour with
> matching nil is obviously 'correct' [...] I figure the decision's 
> fairly arbitrary

It is but it isn't.  I've argued in a separate message why the decision was
made as it was.  It was not, in the end, arbitrary.  It is much more
important that the long form work [the list form] than the short form.
Programs seriously rely on the long form to work.  The short form is used
mostly by humans in cases where parens confuse them.  Parens never confuse
programs.  People should learn not to fuss so much over the one extra set
of parens and just always use the long form becuase it is more general.
The short form was, arguably a mistake, because it leads to an inherent
ambiguity but that mistake is not rendered better by making the short-form
work at the expense of the long form.  It is critical to have CASE work
on multiple matches, and that can only happen if the long form works.
Therefore the long from is not going away, therefore the longform should
not be broken.  It is not critical to have CASE work on single matches since
that is a special case of multiple matches, therefore, choosing in favor of
the single match case is wrong.  Therefore the decision is not, in the end,
arbitrary because additional arbitrary truths about the context of typical
use make the decision that was chosen principled (taken within context).
Hope that helps.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <nms*SY43n@news.chiark.greenend.org.uk>
In article <···············@world.std.com>,
Kent M Pitman  <······@world.std.com> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> All I was saying is I dispute the suggestion that the behaviour with
>> matching nil is obviously 'correct' [...] I figure the decision's 
>> fairly arbitrary
>
>It is but it isn't.  I've argued in a separate message why the decision was
>made as it was.  It was not, in the end, arbitrary.  It is much more
>important that the long form work [the list form] than the short form.
>Programs seriously rely on the long form to work.  The short form is used

If the short forms are a recent addition and legacy code relies on the
case statement behaving exactly as though only the long form were
allowed, that argument seems perfectly reasonable to me. It's just the
idea that the 'alternative' semantics inherently treat 'nil' any more
specially than the current ones do that I don't agree
with. Compatibility with historical accident is fine.

>mostly by humans in cases where parens confuse them.  Parens never confuse

...or maybe they just don't want to make extra lists when it shouldn't
really be necessary.

>programs.  People should learn not to fuss so much over the one extra set
>of parens and just always use the long form becuase it is more general.

Given a choice between retaining only the short form or the longer, yes
I'd go with the longer. But seeing as the short form is on offer, then
if it weren't for legacy code I don't see that the choice is obvious.

>The short form was, arguably a mistake, because it leads to an inherent
>ambiguity but that mistake is not rendered better by making the short-form
>work at the expense of the long form.  It is critical to have CASE work

I'm not suggesting it is rendered any better.

>on multiple matches, and that can only happen if the long form works.

...or people bother to write code such that (nil ...) clauses don't
appear if they want to match nils in lists in following clauses.

>Therefore the long from is not going away, therefore the longform should

(I'm happy for it not to.)

>not be broken.  It is not critical to have CASE work on single matches since

FSVO 'broken'.

>that is a special case of multiple matches, therefore, choosing in favor of
>the single match case is wrong.  Therefore the decision is not, in the end,
>arbitrary because additional arbitrary truths about the context of typical
>use make the decision that was chosen principled (taken within context).

Assuming that the question of legacy code underlies this argument, I'm
perfectly happy with it. All I'm saying is that if you insist on
mixing short forms and long forms in case statements, there's nothing
inherent in the semantics which makes the choice obvious. I didn't
think such a statement would be such a big deal. I've taken pains to
make it clear that I don't think being able to match (nil (...)) would
be an improvement.

-- Mark
From: Pierre R. Mai
Subject: Re: case query
Date: 
Message-ID: <87wvwh4rrj.fsf@orion.dent.isdn.cs.tu-berlin.de>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> If the short forms are a recent addition and legacy code relies on the
> case statement behaving exactly as though only the long form were
> allowed, that argument seems perfectly reasonable to me. It's just the

No that's not the way it works.  _New_ code relies on the existence of 
a general, consistent long form, and it will continue to do so,
because the short form is not, and will never be general and
consistent enough for use in computer generated code (i.e. macros).
Remember also t and otherwise.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Kent M Pitman
Subject: Re: case query
Date: 
Message-ID: <sfwn1xdoenu.fsf@world.std.com>
····@acm.org (Pierre R. Mai) writes:

> Mark Carroll <·····@chiark.greenend.org.uk> writes:
> 
> > If the short forms are a recent addition and legacy code relies on the
> > case statement behaving exactly as though only the long form were
> > allowed, that argument seems perfectly reasonable to me. It's just the
> 
> No that's not the way it works.  _New_ code relies on the existence of 
> a general, consistent long form, and it will continue to do so,
> because the short form is not, and will never be general and
> consistent enough for use in computer generated code (i.e. macros).
> Remember also t and otherwise.

thank you, Pierre.  This says what I wanted to say and I was going to be
too lazy to follow this up further, so I'll just add my nod behind this.
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <oQx*ow53n@news.chiark.greenend.org.uk>
In article <··············@orion.dent.isdn.cs.tu-berlin.de>,
Pierre R. Mai <····@acm.org> wrote:
>Mark Carroll <·····@chiark.greenend.org.uk> writes:
>
>> If the short forms are a recent addition and legacy code relies on the
>> case statement behaving exactly as though only the long form were
>> allowed, that argument seems perfectly reasonable to me. It's just the
>
>No that's not the way it works.  _New_ code relies on the existence of 
>a general, consistent long form, and it will continue to do so,
>because the short form is not, and will never be general and
>consistent enough for use in computer generated code (i.e. macros).
>Remember also t and otherwise.

...which you can look out for, and which you may happen to know can't
come up in that particular circumstance. But, I'm not sure why you're
disagreeing with me, as nowhere do I claim that new code doesn't rely
on a general, consistent long form; I do see the value of it.

-- Mark
From: Vassil Nikolov
Subject: Re: case query
Date: 
Message-ID: <l03130300b3a3e299c8b2@195.138.129.100>
On 1999-07-03 15:03 +0000,
Kent M Pitman wrote:

  [...]
  > The short form was, arguably a mistake, because it leads to an inherent
  > ambiguity
  [...]

Who was it that said that syntactic sugar leads to cancer of the semicolon?




Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: Gareth McCaughan
Subject: Re: case query
Date: 
Message-ID: <86btdp3bxh.fsf@g.pet.cam.ac.uk>
Vassil Nikolov wrote:

> Who was it that said that syntactic sugar leads to cancer of the semicolon?

Alan Perlis. He appears to have said just about everything else, too. :-)

-- 
Gareth McCaughan            Dept. of Pure Mathematics & Math. Statistics,
················@pobox.com  Cambridge University, England.
From: Steve Long
Subject: Re: case query
Date: 
Message-ID: <377C09B6.3AA3D7B8@isomedia.com>
Mark Carroll wrote:

> Currently I do something of the form,
>
> (case (or x 'is-nil) ... (is-nil ...))
>
> Is there a nicer way to make case able to match nil? I was surprised
> to find it refuses, given that (eql nil 'nil) is true.
>
> Hope I'm not asking too much of this sort of thing - it's just easy
> to fall into bad style in Lisp through not knowing enough to pick a
> good workaround.
>
> If I missed something in the FAQ, a pointer will do!
>
> -- Mark


The advantage of "case" is that it doesn't have to evaluate it's tags,
and you can't have a nil tag. If you want something that evaluates tags,
use "cond".

Steve Long
-----------------------------------------------
http://www.isomedia.com/homes/slong
From: Mark Carroll
Subject: Re: case query
Date: 
Message-ID: <dkx*aFY3n@news.chiark.greenend.org.uk>
Thank you very much, everybody! It seems that Paul Hudson wasn't quite
telling me the whole story, but the book's great nonetheless. (-:
Thanks also for mentioning the CLHS, which I've now found a local copy
of, which doesn't really make things clear in the text but an example
says it all.

-- Mark