Why is Common Lisp case insensitive?
Asked Answered
G

4

24

Is there an advantage to defining a function like (defun hi () "Hi!") and be able to call it by using (hi) or (HI) or (Hi), or to (setf a-number 5) and be able to access that number using a-number, A-NUMBER, or A-Number?

If there is such an advantage, then why are most other languages case-sensitive?

Gertudegerty answered 11/9, 2011 at 0:25 Comment(0)
O
36

Using case sensitive names in code within an interactive session is just more error-prone: one not only has to get the characters, but also their case right and there might be several identifiers whose names only differ in case.

Common Lisp is case sensitive. It is just that the Common Lisp reader functionality by default converts all unescaped characters of symbols to uppercase. This is also defined in the Common Lisp standard. The predefined Common Lisp symbols are also all uppercase internally.

a symbol is internally upcase:

CL-USER 3 > 'defparameter
DEFPARAMETER

The input case by default does not matter:

CL-USER 4 > 'deFParameTER
DEFPARAMETER

CL-USER 5 > 'DEFPARAMETER
DEFPARAMETER

a symbol has an upcase name:

CL-USER 6 > (symbol-name 'defparameter)
"DEFPARAMETER"

how many symbols are in the CL package:

CL-USER 7 > (length (apropos-list "" "CL"))
978

Is every symbol in the CL package upcased?

CL-USER 8 > (every (lambda (symbol)
                     (every (lambda (c)
                              (eql c (char-upcase c)))
                            (symbol-name symbol)))
                   (apropos-list "" "CL"))
T

Using uppercase was common on old machines. Remember, the design of Common Lisp started in the early eighties (1982) and a goal was compatibility with earlier Maclisp and when there were more types of computers to support (like the so-called Mini Computers and Mainframes). Other programming languages used on older computers also use uppercase identifiers, like COBOL or PL/1.

Also note that Lisp often was used interactively, so that during an interactive programming session getting the case of names right is more difficult. It is slightly easier when the Lisp reader uses a default case (here uppercase) and converts all input to this case.

Common Lisp supports other reader modes and you can also escape symbols: |This is a Symbol with mixed CASE and spaces|.

Today a lot of software is either lowercase or even case sensitive with lowercase preferred. Some Lisp vendors provide a non-standard variant of Common Lisp, where all symbols by default are lowercase and the reader is case preserving. But this makes it incompatible with standard Common Lisp, where the expectation is that (symbol-name 'cl:defun) is "DEFUN" and not "defun".

Outroar answered 11/9, 2011 at 2:45 Comment(0)
S
17

For interactive sessions, the case unsensitivity used to be the default when the Common Lisp standard was defined.

But, what truly happens is that the Common Lisp reader converts all symbols to upcase before interning and evaluating it. That is the default, but you can always change it if you want.

The *readtable* objects has an attribute, readtable-case, that controls how the reader interns and evaluates the symbols read. you can setf readtable-case to :upcase(default), :downcase, :preserve, :invert.

By default, the readtable-case is set to :upcase, which causes all symbols to be converted to upcase.

If you want case sensitivity, you should do

(setf (readtable-case *readtable*) :invert)
=> :invert

At a first glance, you might think that it would be better to choose the :preserve option, but it has some minor issue: all the symbols, as defined by the standard, must be upcased. So, you would have case sensitivity to the symbols defined by you only, and would have to do write:

* (DEFUN hi () "Hi!")
=> hi
* (SETF a-number 5)
=> a-number
* (HI)
=> ;error: the stored function is #'HI in the *readtable*, but by 
   ;       calling (HI) you try to acces a function named #'hi(downcase), which
   ;       gives an error
* A-NUMBER
=> ;error: same for the variable
* (hi)
=> "Hi!"
* a-number
=> 5

The :downcase option is the opposite of the default, converting everything to downcase, giving you no case sensitivity.

But with :invert, the symbols you write in the source code, like defun, setf the hi function, get converted to upcase, and any symbol in CamelCase is preserved like it is originaly:

* (setf (readtable-case *readtable*) :invert)
=> :invert
* (defun Hi () "Hi!")
=> Hi
* (Hi)
=> "Hi!"
* (eq 'Hi 'hi)
=> nil
* (eq 'HI 'hi)
=> nil
* (eq 'Hi 'Hi)
=> t
Stableboy answered 18/2, 2014 at 21:8 Comment(1)
This clarifies everything a little more. (setf (readtable-case *readtable*) :invert) reverses all uppercase letters to lowercase and all upper case to lowercase because all the original functions are written in uppercase by default.Erminois
G
9

(As others have pointed out, it is actually case-sensitive, but standard reader behaviour is to upcase everything.)

As to the advantages:

  • Do you really want Hashtable and HashTable to be naming different things?
  • Since Common Lisp provides different namespaces, you also do not need capitalization to tell class, variable, and function names apart (among others). You can have a class name and a function name with no ambiguity. Name can even be the name of a variable, on top of that.
  • As seen in the last sentence, you can capitalize symbol names in prose just like any other words.
Guenna answered 11/9, 2011 at 9:4 Comment(2)
Good points! But if Hashtable and HashTable should unambiguously point to the same thing, shouldn't name also point unambiguously to a function, class, or variable?Gertudegerty
@wrongusername: It is unambiguous. When you have an evaluated form (name foo), it is unambiguously a function name; when you have (defmethod bar ((baz name)) ...), it is unambiguously a class name (or rather type...); when you see an evaluated form (quux name), it is unambiguously a variable. It is just the same as you can use "name" as both a verb and a noun in english without confusion.Guenna
F
3

By default the reader in CL is case converting, all escaped characters get turned into uppercase. You can customize this behavior with readtable-case. This is because its easy to interface with other languages that follow the same conventions.

Fredel answered 11/9, 2011 at 0:34 Comment(4)
Hm, what languages do CL interface with?Gertudegerty
At the time? Probably Fortran. Remember that Common Lisp and its predecessors were designed a long time ago in a galaxy far, far away.Borne
It was not especialy Fortran, it was that often the härdware (the Teletype) was uppercase and the OS was using uppercase. Thus the programming languages also used uppercase: PL/1, Cobol, Fortran, Lisp, ... It was kind of painful to edit case sensitive commands on a terminal attached via slow connections in line-editing modes, ...Outroar
@Rainer Thanks for the insight. I was assuming Fortran and other languages were the reason for the convention.Fredel

© 2022 - 2024 — McMap. All rights reserved.