The index for the Allegro CL Documentation is in index.htm. The documentation is described in introduction.htm.
This document contains the following sections:
1.0 Introduction to case in Allegro CLIn standard Common Lisp, the reader converts all unescaped lowercase characters to uppercase, so that for example Foo and foo are both read as FOO. The fact that Upper Case mode exists shows how long Lisp has been around. When Lisp started there were primarily upper case input devices. When lower case capability started to appear, the simplest way to handle those lower case characters was to simply convert them to upper case. This conversion didn't matter since everything worth naming was case insensitive as well, such as file names and names of library functions written in Fortran or assembler.
Technology marches on and eventually upper-case-only input devices
were retired. The Unix operating system spread all over the world and
introduced a filesystem and programming language that are
case-sensitive with lower case being the normal case for names. Upper
Case mode is very inconvenient for naming objects in the Unix
world. Thus Lower Case mode was introduced, first popularized in Franz
Lisp and then in Allegro Common Lisp. The Windows operating system has
even gone further in naming objects in a case dependent matter, with
nearly every API function using dual cases
(e.g. SetWindowTitle
).
Creating a new mode for Lisp would be detrimental if the result was that it fractioned the Lisp world. Fortunately this wasn't the case. It turned out to be very easy to write programs that could work in either mode. At the end of this document we will show the coding style that results in programs portable between the modes. Allegro Common Lisp is itself a good example of a large Lisp program that can work in any case mode.
There are two parameters that determine the reader's actions:
casepreference and casesensitivity. The
preferred case is either upper or lower, and refers to
the case of the characters in the print names of all of the standard
symbols, such as car
and cdr
. Case
sensitivity can be either sensitive or insensitive to
case. Case-sensitive means that the Lisp reader does not modify the
case of any characters it reads. Case-insensitive means that
characters that are not of the preferred case are converted to the
preferred case.
Thus, there are four possible values for the combination of case preference and case sensitivity. However, only three are supported in Allegro CL.
Case-insensitive, uppercase-preferred. This is the mode used in standard Common Lisp and in most of the older Lisps such as MacLisp. With this mode you can even enter Lisp programs with a card punch. This is the most portable mode.
Case-sensitive, uppercase-preferred. This is the mode used by InterLisp and the mode that Allegro CL no longer supports.
Case-insensitive, lowercase-preferred. This mode is similar to the case-insensitive, uppercase-preferred mode. This mode is useful if you are reading files designed for a case-insensitive Lisp into a case-sensitive, lowercase preferred Lisp.
Case-sensitive, lowercase-preferred. This is the mode used by many modern languages, including, for example, the C programming language. It matches the conventions of Unix and thus is the most natural mode to use for some programmers.
The functions set-case-mode and convert-mixed-case-symbols, and two variables
*current-case-mode*
and *ignore-package-name-case*
are provided for
controlling and sensing case modes.
So, Allegro Common Lisp can operate in three different case modes. In this document we will go into more detail on the two important modes and describe their advantages and disadvantages. We'll show how to write code that works in any mode.
There are three supported modes. :case-sensitive-lower
and :case-insensitive-upper
are the primary modes. The
third, :case-insensitive-lower
is useful for porting code
between the two primary modes.
(The Quick Brown Fox)
becomes (THE
QUICK BROWN FOX)
. We'll refer to this as Upper Case mode.Late in the standardization of Common Lisp the designers realized
the case sensitivity was important to Lisp users. At this point the
rest of computing world was in Lower Case mode using case sensitive
filenames and function names with lower case being the preferred
mode. Rather than switch Common Lisp to Lower Case mode they chose
instead to add a readtable attribute called
readtable-case. The function readtable-case accesses (and with setf sets) the readtable-case of a
readtable object. When readtable-case is set to
:invert
, case is preserved except that the case is
inverted for symbols whose names are all the same case. Thus given a
string you can't tell how to present it to the user unless you know
where the string came from and thus can tell if it's a normal or an
inverted symbol-name string. We'll use the term Inverted
mode to describe the situation when readtable-case is
:invert
.
If you chose to use readtable-case in your program then you should not use set-case-mode as well. They are two independent methods for altering the reader and printer behavior and in order to keep them from conflicting with each other we've done the following:
:case-insensitive-upper
. In this mode readtable-case
has the effect specified in the Common Lisp spec.:case-sensitive-lower
then for the purposes of
printing and reading Lisp assumes that the readtable case of all readtables is :preserve
.
Lisp won't actually change the readtable-case nor will you see :preserve
returned by the readtable-case function. :case-insensitive-lower
then the reader and
printer act as if the readtable-case of all readtables was set to :downcase
.
Again, this forcing readtable-case to :downcase
is an
internal change only.At this point you should decide if you want to achieve case
sensitivity by using the :invert
value for readtable-case
(and thus having to work with some case inverted strings), or by using
set-case-mode. If you decide to use readtable-case then you can stop
reading this document. If you want to use set-case-mode then read
on.
Before describing how to make code case-mode portable we will examine the cost of such portability. If you're working in Upper Case mode then there is little to lose by keeping the code portable. You only have to remember a few coding conventions and you can share your code with your friends who use Lower Case mode.
If you like to work in Lower Case mode then portability to Upper
Case Mode may cost you the ability to use the full expressibility of
the Lower Case mode. For example you may want to use the convention
that your Clos class names are capitalized. Thus you might have a
class Box
and set the value of the symbol
Box
to the Box
class object. You might also
have another symbol named box
whose value is an instance
of a the class Box
. This will work fine in Lower Case
mode. However when you try reading this code in Upper Case mode the
symbols Box
and box
will both end up being
the same symbol whose symbol-name is "BOX".
You could port more easily from Lower Case mode to Inverted Mode, but doing so depends on the target of the port being able to deal with an Inverted Mode module. Most projects seem to be in either Lower Case mode or Upper Case mode.
Lower Case mode gives you a lot more expressibility than Upper Case mode. If you use Lower Case mode and are concerned about porting your code to Upper Case mode then you must constrain yourself to what Upper Case mode can support. This is the cost of portability.
If portability of your code between the various case modes is important, then here are some thing you should do:
Packages are named by strings and are looked up in a case sensitive
manner. In Lower Case mode the standard package names are all in lower
case and in Upper Case mode they are in upper case. Thus a good way to
refer to package is not by a string e.g. "common-lisp-user"
but by a symbol such as :common-lisp-user
or
#:common-lisp-user
. Putting the symbol in the keyword
package or using an uninterned-symbol keeps from cluttering the
current package (and maybe causing symbol clashes).
Symbols can be used nearly everywhere a package name is needed. The functions that look for package names use the symbol-name of a symbol passed as an argument. By doing
(in-package :ole)
you end up calling in-package with "ole" in Lower Case mode or "OLE" in Upper Case mode, and thus the package is found regardless of the mode.
A global solution to matching package names is to set the variable
*ignore-package-name-case*
. When the value of
that variable is true, package name to package lookup is done in a
case insensitive manner.
In package definitions you also want to use symbols in place of strings, as in:
(defpackage :foreign-functions (:nicknames :ff) (:use :common-lisp :excl) (:export #:def-foreign-call #:def-foreign-type #:defun-foreign-callable #:def-foreign-variable ))
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)))
When reading and testing against symbol names you'll want the code
to work regardless of the case of the print names. This can be
accomplished by using case-insensitive predicates (such as
equalp). Another possibility is to use (string
:foo)
rather than "foo" or "FOO" so that
the correct string for the current case mode is used at runtime.
Generally Upper Case mode code can be made portable by looking for and fixing the few items we've mentioned above. However you may encounter code written in a style such as this:
(DeFun Foo (x y) (Cond ((PlusP x) (Sqrt y)) (t y)))
The author of this code is taking advantage of the fact that in
Upper Case mode the case of symbols in the source code doesn't
matter. In order to port this to Lower Case mode you could go through
and lowercase every symbol naming an official Lisp form. The author of
the code is unlikely to want the code back after such a
transformation, as he must see some value to his style of
capitalization. A way to make this code readable into Lower Case lisp
without modifying it is to switch the lisp to
:case-insensitive-lower
mode. In this mode, the strange
symbol names will be downcased. After reading in this file the mode
can be switched back to :case-sensitive-lower
mode.
Note that when you switch to :case-insensitive-lower
mode the value of *print-case*
determines how symbols will be
printed. The initial value of *print-case*
is :upcase
. Thus
unless you change *print-case*
you'll find that when
you switch to :case-insensitive-lower
, symbols will start
printing in upper case even though their print names are in lower
case. If this annoys you, you can set *print-case*
to :downcase
.
Copyright (c) 1998-2000, Franz Inc. Berkeley, CA., USA. All rights reserved. Created 2000.10.5.