So what's up with the #:uninterned symbols?
The special syntax sharp-colon (#:) creates an "uninterned
symbol." This is a symbol with no package at all, and is
different from both normal symbols and keyword symbols.
A new uninterned symbol is created by the reader every time
you use it.
Uninterned symbols are not keywords! They follow the same
evaluation rules as normal symbols. So if you type :FOO at
the REPL prompt, it evaluates to itself and you get :FOO
back. But if you type #:FOO, the interpreter tries to
evaluate the newly-created symbol, which doesn't have a
value (because it was just created) so you get an error.
Uninterned symbols are used to prevent name conflicts in the future. For example, the following code example (from Pascal Bourguignon) produces an error:
(in-package :cl-user) (defpackage mypackage (:use common-lisp) (:export foo bar)) (use-package 'mypackage)
To understand why, we need to look at what is happening on
each line. The first line sets the current package to
CL-USER. Then the second line defines a new package,
MYPACKAGE, with two exported symbols, FOO and BAR. But when
the Lisp reader encounters FOO and BAR, it reads them in the
context of the current package, which is still CL-USER.
So, the reader interns two new symbols, CL-USER::FOO and
CL-USER::BAR.
On the last line, (USE-PACKAGE 'MYPACKAGE) tries to import
MYPACKAGE:FOO and MYPACKAGE:BAR into CL-USER, but we've
already defined CL-USER::FOO and CL-USER::BAR! The
interpreter doesn't know which FOO and BAR are the right
ones, so we get a "name conflict."
To prevent this kind of error, we can use uninterned symbols:
(defpackage #:mypackage (:use #:common-lisp) (:export #:foo #:bar))
But in fact, DEFPACKAGE (and many other commonplace macros)
only cares about the name of the symbol, not the symbol
itself. The CLHS calls these arguments "symbol
designators." Symbol designators can be uninterned symbols,
as above, or keyword symbols, or strings. So either of
the following will also work:
(defpackage :mypackage (:use :common-lisp) (:export :foo :bar)) (defpackage "MYPACKAGE" ; remember symbol names get (:use "COMMON-LISP") ; converted to upper case (:export "FOO" "BAR")) ; by the Lisp reader
So which one should you use? As discussion on the mailing list showed, there's no simple answer. Using keywords wastes memory, since all those symbols get interned in the KEYWORD package and then never used again. Using uninterned symbols is slightly inefficient, since a new symbol has to be created each time you use it. Using strings makes your code non-portable to Lisps that do not convert symbol names to upper case, such as Allegro CL in "modern" mode.
As Peter Seibel pointed out, it may not really matter, since the compiler may convert whatever form you use into strings.
The most common style seems to be to use keywords for package names and uninterned symbols for exports:
(defpackage :mypackage (:use :common-lisp) (:export #:foo #:bar))
This makes sense given that you'll probably need to refer to
the package name again in a USE-PACKAGE somewhere, so you
might as well leave the symbol interned (defined) in the
KEYWORD package. You probably won't be using :FOO and :BAR
again as keywords, so there's no need to keep them hanging
around in the KEYWORD package.
The bottom line? Uninterned symbols are useful for places where you need to refer to a symbol by name before you actually define it. Unlike keywords, they don't hang around for the rest of your program, and they are a bit more portable than strings.
By Stuart Sierra, with help from the CL Gardeners mailing list.