Subject: [clisp-list] Case Handling Proposal.

From: Marco Antoniotti <[email-masked]>
Date: Tue, 14 Nov 2000 09:55:01 -0500

Hi

I'd like some feedback on the proposal I made on C.L.L. regarding the
"case sensitivity" issue.

I believe this proposal goes in a direction that is already present in
CLisp (as a matter of fact I inspired myself to it).  So I'd like some
feedback especially w.r.t. what the CLisp team thinks about it, and -
if liked - what it'd take the CLisp team to implement it.

Of course the proposal will have to be amended here and there.

Cheers

Marco

==============================================================================
Since the crux of the problem is two-fold - case sensitivity and symbol
lookup - the personal opinion I formed is that this issue should be
addressed at the package level.  I believe that tagging a package with
a (readtable) case may be the right solution.  CLisp already hase
something similar.

So the idea would be to do the following

1 - Changes to DEFPACKAGE.

	(defpackage "FOO" (:use "COMMON-LISP")
           (:nicknames "foo")  ; Just to show that you can accomodate this.
           (:symbol-name-case <an extended readtable case tag>)
           (:export "ZUT"
                    "gnao"
                    "Bar"
                    "qWe"
                    #:a-Symbol
		    #:another-symbol
                    #:AND-ANOTHER
		    #:|an-Escaped-symBOl|
                    #:|a Funky symBOl|))

The :SYMBOL-NAME-CASE option will have effect on the way in which
symbols are looked up in the package. It will have one of the
following values:

	- :PRESERVE
          The symbol names are INTERNed in the package literally¹.
	  The symbol names are to be looked up literally.  I.e. the
	  reader, *after* having read in the symbol and having done
	  its processing according to READTABLE-CASE looks up the
	  symbol name in the appropriate package.  The match must be
	  done as if through STRING=.

	- :UPCASE
          The symbol names are INTERNed in the package after a
          STRING-UPCASE equivalent operation has been performed on them.
	  The symbol names are to be looked up literally.  I.e. the
	  reader, *after* having read in the symbol and having done
	  its processing according to READTABLE-CASE looks up the
	  symbol name in the appropriate package.  The match must be
	  done as if through STRING=.

	- :DOWNCASE
	  As per :UPCASE, with STRING-DOWNCASE.

	- :INVERT
	  As per :UPCASE, with STRING-INVERT-CASE²

	- :IGNORE
          The symbol names are INTERNed in the package literally¹.
	  The symbol names are not to be looked up literally.  I.e. the
	  reader, *after* having read in the symbol and having done
	  its processing according to READTABLE-CASE looks up the
	  symbol name in the appropriate package.  The match must be
	  done as if through STRING-EQUAL.
	  The value of :IGNORE is the default.

The system packages (most notably :COMMON-LISP) and the legacy
packages will just need to add a

	(:symbol-name-case :ignore)

or, when so explicitely desired,

	(:symbol-name-case :uppercase)

1.1 - Examples of interaction among the parameters <... omissis ...>

1.2 - Problems

The main problem to address in this setup is what to do with inherited
symbols.  There are many cases to consider³, however, the following
changes should suffice.

2 - Changes to IMPORT (and to SHADOWING-IMPORT).

IMPORT (and SHADOWING-IMPORT) must be limited.

IMPORT of a symbol in a package with :SYMBOL-CASE-NAME set to :IGNORE
or :PRESERVE is allowed without restrictions.

IMPORT of a symbol in a package with :SYMBOL-CASE-NAME set to :UPCASE
or :DOWNCASE or :INVERT is allowed if and only if the SYMBOL-NAME of
the symbol being imported is STRING-EQUAL to the result of applying
STRING-UPCASE, STRING-DOWNCASE or STRING-INVERT-CASE to the symbol
SYMBOL-NAME itself.  Otherwise a condition of type PACKAGE-ERROR (or a
new appropriate one) is signalled.

3 - Inherited symbols.

Since USE-PACKAGE makes symbol "assessible" but not "present" in the
package "issuing" the call, no changes are needed at the interface
level. The lookup of the inherited symbol is done through the current
package, using the features of the used package.

4 - Changes to FIND-SYMBOL.

See comments about DEFPACKAGE.

5 - Changes to MAKE-PACKAGE.

MAKE-PACKAGE will accept the a new keyword :SYMBOL-NAME-CASE with
possible values as described above.

6 - New Function PACKAGE-SYMBOL-NAME-CASE.

A new accessor to retrieve the the aforementioned property.

7 - Changes to LOAD (not strictly necessary).

LOAD should take an extra keyword argument named :READTABLE-CASE,
which will set the value of (a copy of) (READTABLE-CASE *READTABLE*)
before starting to READ the input contents.

8 - Examples

The case of the "CLJava" translator proposed by John Foderaro can be
dealt as follow

	(setf (readtable-case *readtable*) :preserve)

	(defpackage "Java" (:use "COMMON-LISP")
           (:symbol-name-case :preserve)
   	   (:export "addMouseListener" "this"))

	(defpackage "CLJava" (:use "COMMON-LISP")
           (:symbol-name-case :preserve)
	   (:import-from "Java" "addMouseListener" "this")
           (:export "init" "getImage" "getCodeBase"))

	(in-package "CLJava")

	(def-java-method init () void
            :public
          (setq notImage   (getImage (getCodeBase) "images/not.gif")
	        crossImage (getImage (getCodeBase) "images/cross.gif"))
  
          (addMouseListener this))

In the example you could also write

	(defpackage "CLJava" (:use "COMMON-LISP" "Java")
           (:symbol-name-case :preserve)
           (:export "init" "getImage" "getCodeBase"))

9 - Costs

The costs are the estimated to be the following

	a - Impact on existing code:
            Unable to estimate.  It would seem that the current
            practice of writing CL code all lower case should remain
            unaffected.  With :SYMBOL-CASE-NAME set to :IGNORE (the
            proposed default) the *PRINT-CASE* problem (when set to
            :DOWNCASE) would seem to go away.

	    Packages written with the current uppercase style will
	    continue to function without change.

        b - Impact on existing implementations:
            Moderate: the implementors must add all the code to
            support the proposed change.  The most vexing problem will
            be to modify the behavior of FIND-SYMBOL and IMPORT to
            accomodate the different proposed cases.

	c - Impact on performance:
	    "Interpreted" code will - most likely - suffer a
	    performance hit because of the added complexity in
	    FIND-SYMBOL.
	    "Compiled" code will - most likely - not be affected by
	    the changes proposed, except in the cases where a
	    FIND-SYMBOL is inserted by the compiler in a way beyond
	    user control.

ADVANTAGES:

These are the advantages I see in the above proposal (to paraphrase
John Foderaro):

    Existing Common Lisp programs and systems are still Common Lisp
    programs and systems.

    Programmers are not required to follow any special coding standard
    unless so required by the declaration of a third party DEFPACKAGE
    declaration (or MAKE-PACKAGE invocation).

    New code written in a :PRESERVE READTABLE-CASE can be made to work
    in any system under programmer control.  The :IGNORE default of
    the legacy packages and the :USE and IMPORT
    (cfr. SHADOWING-IMPORT) rules will ensure that they will not
    interfere with the :PRESERVE READTABLE-CASE being used.
    It is assumed that the new code will be put in packages with
    :SYMBOL-CASE-NAME set to :PRESERVE.

    There is no need for separate "images" to be provided by each
    implementor.

    Portability is ensured to a greater degree than just addressing
    the problem at the READTABLE-CASE level.  People are forced to
    make a decision about declaring how their package work and to
    advertise this fact.  Their code works in all conforming (to this
    proposal that is) implementations; i.e. how their code works is
    totally under the programmers' control, and they are not
    restricted to the decision on READTABLE-CASE (which could be left
    to :UPCASE) made by a given implementation.

DISADVANTAGES:

I foresee the following disadvantages. Actually only one.

    Given the (IMHO moderate) burden on the vendors and the
    implementors it may be that some systems will not implement
    the proposed changes.  If the proposal will ever be adopted it
    will be the burden of the community to ensure that the vendors and
    the implementors will eventually conform.

¹ This is the current ANSI default.
² The function STRING-INVERT-CASE (and NSTRING-INVERT-CASE) must be
  defined appropriatedly and inserted in the standard.
³ I know I might be missing a lot here.
==============================================================================

-- 
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