Allegro Common Lisp can operate in three different case modes. These modes are described in the Allegro reference manual. In this document we will go into more detail on the important modes and describe their advantages and disadvantages. We'll show how to write code that works in any mode.
The two important modes are:
The fact that Upper Case mode exists shows how long Lisp has been around. When Lisp started there were only 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 Fortan 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 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.
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 prefered mode. Rather than cleanly switch Common Lisp to Lower Case mode they chose instead to put a patch over the current design in the form of a readtable attribute called readtable-case. 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 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 to 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 eachother we've done the following:
You may recall a fourth case mode (:case-sensitive-upper). This mode is no longer supported (you can set the mode but the effect on the printer are undefined).
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 covention 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 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 however that's relies 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 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 in all 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 the variable *ignore-package-name-case* which when true causes the package name to package lookup to be 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 possbility 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 advantange 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 default 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 can you can set *print-case* to :downcase.