From: David Bakhash
Subject: a problem with Franz's case suggestions
Date: 
Message-ID: <m37l684ri4.fsf@cadet.dsl.speakeasy.net>
Hi,

I've been doing more thinking about Franz's whole case thing, and
about the different proposed solutions that have been suggested.  But
I've noticed yet another problem with Franz's way of seeing things.

In the file $ACL_HOME/doc/cl/case.htm

you'll see the following advice:

============

5.3 Creating symbols

The most common non-portable form we come across looks like this

(defun constructor (struct) (intern (format nil "MAKE-~a" struct)))

This assumes that this code will run in Upper Case mode. Writing it as this allows the
case of the "make-" to be determined by the case of the :make- symbol's printname, which
will be correct for the case mode:

(defun constructor (struct) (intern (format nil "~a~a" :make- struct)))

============

The problem I see with this is that you're depending on *print-case*.
In fact, if *print-case* is :lower, which I like it to be (especially
since it prints out symbols in the CL package in lower-case, which are 
then read back into upper-case when readtable-case is set to :invert), 
then Franz's whole portability thing is broken, isn't it?

dave

From: Tim Bradshaw
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <nkju29bkgyk.fsf@tfeb.org>
David Bakhash <·····@alum.mit.edu> writes:

> The problem I see with this is that you're depending on *print-case*.
> In fact, if *print-case* is :lower, which I like it to be (especially
> since it prints out symbols in the CL package in lower-case, which are 
> then read back into upper-case when readtable-case is set to :invert), 
> then Franz's whole portability thing is broken, isn't it?
> 

If that's their suggestion, then yes it is.  In fact precisely this
kind of thing is exactly the sort of lossage I've found in various
programs which never thought about *print-case*.

I think to be really *sure* you should wrap your code in
(with-standard-io-syntax ...).  What I tend to end up doing is

(format nil "~A" (symbol-name '#:foo))

which is not quite so good.

I think what I actually ended up doing was something like this:

(defun symbolify (&rest things)
  (intern (apply #'concatenate 'string
		 (mapcar #'(lambda (x)
			     (etypecase x
			       (string x)
			       (symbol (symbol-name x))))
			 things))))

but this doesn't do everything, because you can't choose the package
easily.  I like it though because it doesn't go anywhere near the
printer, which seems like better to me.

--tim
From: John Foderaro
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <MPG.1479b03c83701a1298969d@news.dnai.com>
In article <··············@cadet.dsl.speakeasy.net>, ·····@alum.mit.edu says...
> The problem I see with this is that you're depending on *print-case*.
> In fact, if *print-case* is :lower, 

Ok, assume that when this function is run, *print-case* is lower
and go back to the original function in the code:

(defun constructor (struct) (intern (format nil "MAKE-~a" struct)))


what will the name that this function creates look like?

Won't it be something like  MAKE-foo ?

Isn't the code surrounding this function likely to have bound
*print-case* to :upcase just so that doesn't happen?

So in practice what we've suggested isn't a problem but of course
it can't hurt to bind *print-case* around format call just
to be sure (or to use (symbol-name :make-) to get *print-case*
out of it entirely).
From: Marco Antoniotti
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <y6cofzjsikb.fsf@octagon.mrl.nyu.edu>
John Foderaro <···@unspamx.franz.com> writes:

> In article <··············@cadet.dsl.speakeasy.net>, ·····@alum.mit.edu says...
> > The problem I see with this is that you're depending on *print-case*.
> > In fact, if *print-case* is :lower, 
> 
> Ok, assume that when this function is run, *print-case* is lower
> and go back to the original function in the code:
> 
> (defun constructor (struct) (intern (format nil "MAKE-~a" struct)))
> 
> 
> what will the name that this function creates look like?
> 
> Won't it be something like  MAKE-foo ?
> 
> Isn't the code surrounding this function likely to have bound
> *print-case* to :upcase just so that doesn't happen?
> 
> So in practice what we've suggested isn't a problem but of course
> it can't hurt to bind *print-case* around format call just
> to be sure (or to use (symbol-name :make-) to get *print-case*
> out of it entirely).

Except that you end up polluting the KEYWORDS package.

Cheers

-- 
Marco Antoniotti =============================================================
NYU Bioinformatics Group			 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
             Like DNA, such a language [Lisp] does not go out of style.
			      Paul Graham, ANSI Common Lisp
From: Erik Naggum
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <3183166506151217@naggum.net>
* John Foderaro <···@unspamx.franz.com>
| So in practice what we've suggested isn't a problem but of course
| it can't hurt to bind *print-case* around format call just
| to be sure (or to use (symbol-name :make-) to get *print-case*
| out of it entirely).

  You're big on "no problem in practice", but I am _very_ negative to
  that general attitude towards solving problems.  I want correctness
  and adherence to specifications, not some justification that most of
  the time, most of the carefully worked-out specification does not
  matter, while the safe, general case applies.  There are a number of
  bugs in Allegro CL that have to be coded around by funny bindings and
  fixes because you don't do your job correctly and according to the
  full specification, but assume all sorts of simplifying short-cuts for
  yourself.  That's the New Jersey approach, not what we want in the
  Common Lisp world.

  Now, I'm not sure this is you only, but I have seen the code of many
  engineers at Franz Inc, and I have the greatest respect for their
  work, normally written with visible traces of painstaking attention to
  detail.  I have seen some more of your work and I am not consistently
  impressed, to put it that way.  Yes, it works, most of the time.  Yes,
  it does useful stuff, most of the time.  Yes, it is speedily written
  and satisfies that "we deliver" reuirement.  But it is not _correct_.
  Like, I have been asking for fixes to the code that reads and prints
  symbols for a _very_ long time, only to find some fixes in ACL 6.0,
  but this is _still_ broken:

(2) cl-user
*print-base*
=> 10
(3) cl-user
(let ((*print-base* 16)) (prin1 (list 'DEAD (intern "FACE"))))
(DEAD |FACE|)
=> (DEAD |FACE|)

  It should print (|DEAD| |FACE|) and return (DEAD FACE) in Modern mode,
  but it prints what it does because the first time the escaped print
  name is cached, the base is honored, but it is not _stored_ with the
  optimization, so when it is different, the cache is not invalidated.

  You know about all this, John, since we have discussed it at great
  length.  I argued that until the caching was fixed, it should not be
  enabled and that keeping the base and other parameters with the cache
  was crucial to _correctness_.  The _impression_ I got was that this
  was not veryimportant because "in practice" people didn't fiddle with
  these special variables, but that only means it won't be a problem "in
  practice" either because people who try to use Allegro CL will get
  burned and never try to use the specification to the fullest.  By a
  careful process of introducing such bugs, you lower the value of the
  standard as a tool for good programmers (never mind the mediocre ones
  who epitomize the "in practice" excuse) as a repository of knowledge
  about the language and a treasure of understanding what the language
  _should_ be like.  To imagine that you can destroy all that important
  trust in a community reference simply by optimizing the printing of
  symbols incorrectly!  You'd have to be phenomenally careless about
  other people's time, money, and other values _not_ to think about the
  _consequences_ of making such an optimization.

  So, rather than _defending_ the buggy code in your documentation, the
  responsible thing to do is to admit to the bug and fix it in the next
  release.  I still get these really bad vibes from someone who relies
  on other people to "remember" something that they shouldn't have to
  know about, which is not part of the specification, such as which
  assumptions somebody else made about what the "common crowd" would or
  would not "normally" do, so the "most of the time" could apply.  It
  breaks the simple and elegant and attractive ideas of abstraction and
  encapsulation, too, so we are left with a product that we have to know
  in _much_ more detail than we would need to if you had just done it
  right the first time.

  Finally, I'd like to draw people's attention to what I wrote back on
  2000-11-08 in <················@naggum.net>:

  * John Foderaro
  | If you want to see the "ferociously detailed specs", they are slightly
  | more than one page of html.  Don't blink or you might miss it.
  | 
  | http://www.franz.com/support/documentation/6.0/doc/case.htm#portability-1

    Your code examples break if *print-case* is not :upcase.

    This is just too shoddy work to publish, John.
  
  It gets worse the more you defend it.

#:Erik
-- 
  ALGORITHM: a procedure for solving a mathematical problem in a finite
  number of steps that frequently involves repetition of an operation.
  ALGOREISM: a procedure for solving an electoral problem in a finite
  number of steps that frequently involves repetition of an operation.
From: H�kon Alstadheim
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <m0zoj2hqh6.fsf@alstadhome.cyberglobe.net>
Erik Naggum <····@naggum.net> writes:
[...snip...]
>  By a careful process of introducing such bugs, you lower the value
>  of the standard as a tool for good programmers (never mind the
>  mediocre ones who epitomize the "in practice" excuse)

No, mind us as well please. As a mediocre "in practice" programmer I'd
like to point out that our "in practice" guesstimates have a slightly
less likelihood of bombing if the base system and the libraries adhere
strictly to standards and documented behaviour. In fact, we have a way
of doing things that are "not nice", which quite often touches on the
dusty corners of any standard.

-- 
H�kon Alstadheim, Montreal, Quebec, Canada  
From: David Bakhash
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <m34s1bycx8.fsf@cadet.dsl.speakeasy.net>
John Foderaro <···@unspamx.franz.com> writes:

> In article <··············@cadet.dsl.speakeasy.net>, ·····@alum.mit.edu says...
> > The problem I see with this is that you're depending on *print-case*.
> > In fact, if *print-case* is :lower, 
> 
> Ok, assume that when this function is run, *print-case* is lower
> and go back to the original function in the code:
> 
> (defun constructor (struct) (intern (format nil "MAKE-~a" struct)))
> 
> 
> what will the name that this function creates look like?
> 
> Won't it be something like  MAKE-foo ?
> 
> Isn't the code surrounding this function likely to have bound
> *print-case* to :upcase just so that doesn't happen?
> 
> So in practice what we've suggested isn't a problem but of course
> it can't hurt to bind *print-case* around format call just
> to be sure (or to use (symbol-name :make-) to get *print-case*
> out of it entirely).

John.  I was merely taking code out of the sample in the doc file.
This is how I actually do it in my code:

(defun constructor (stuct)
 (intern (concatenate 'string
                      "MAKE-"
                      (string-upcase (symbol-name struct)))))

This is because I _never_ intern symbols that are anything but
uppercase.  Normally, I write in all lowercase, but it's irrelevant
because readtable-case is set to :upcase for me, nearly all the time,
except where I sometimes set it to :invert, which I find to be an
extremely useful setting that people don't seem to be taking advantage 
of.

dave
From: Thomas A. Russ
Subject: Re: a problem with Franz's case suggestions
Date: 
Message-ID: <ymi4s1b1xz6.fsf@sevak.isi.edu>
David Bakhash <·····@alum.mit.edu> writes:
> 
> (defun constructor (struct) (intern (format nil "~a~a" :make- struct)))
> 
> ============
> 
> The problem I see with this is that you're depending on *print-case*.
> In fact, if *print-case* is :lower, which I like it to be (especially
> since it prints out symbols in the CL package in lower-case, which are 
> then read back into upper-case when readtable-case is set to :invert), 
> then Franz's whole portability thing is broken, isn't it?

Actually, the way this should print according to the standard will be
determined by a combination of readtable-case and *print-case*.  The
interaction is designed to ensure that if you print a symbol name with a
particular combination of readtable-case and *print-case*, using the
same readtable-case will mean you get the same symbol by reading the
output.

====================

22.1.3.3.2  Effect of Readtable Case on the Lisp Printer
     
 When printer escaping is disabled, or the characters under consideration
 are not already quoted specifically by single escape or multiple escape
 syntax, the readtable case of the current readtable affects the way the
 Lisp printer writes symbols in the following ways:

   :upcase 

     When the readtable case is :upcase, uppercase characters are
     printed in the case specified by *print-case*, and lowercase
     characters are printed in their own case.
     
    ...

   :invert 

     When the readtable case is :invert, the case of all alphabetic
     characters in single case symbol names is inverted. Mixed-case
     symbol names are printed as is.

====================

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu