Search code examples
common-lisp

Why do we specifiy packages using pound colon in Common Lisp?


New Common Lisper here. I have seen packages being declared with the pound colon syntax, as in (defpackage #:foo), but I have also seen them defined as plain keywords, as (defpackage :foo).

Which is considered "better"? What is the difference between these two? I read somewhere that pound colon simply means the keyword isn't interned. Is that true? If so, what are the advantages to defining a package with an uninterned keyword?


Solution

  • Package names are strings. But it is a good idea to specify them as symbols, because this buys you immunity to variants of CL which which do not have the same case behaviour as CL. As an example, Allegro CL has (or used to have: I have not looked at it for at least a decade) a mode where everything was lower-case by default. In that mode (symbol-name 'foo) would be "foo", and all the standard CL symbols were lower-case versions of themselves (so (symbol-name 'symbol-name) was "symbol-name".

    If you wanted to write code which had any chance of running in an environment like that, you couldn't give packages names which were strings:

    (defpackage "FOO"
      ...)
    

    would mean that, in future, you'd need to type FOO:x and so on, which was horrible. Even worse, if you said

    (defpackage "FOO"
      ...
      (:export "X"))
    

    You'd now have to type FOO:X. And something like this:

    (defpackage "FOO"
      (:use "CL")
      (:export "X"))
    

    would fail dismally because there was no package whose name was "CL" at all: its name, of course, was "cl".

    So if you needed things to work with that environment you really wanted to type package names – and symbol names in packages – as symbols.

    This also would mean that your code would have a chance of running in some future CL variant which really was lower-case, which many people assumed would probably happen at some point, since case-sensitive lower-case-preferred languages had clearly won by the late 1980s.

    Given that there's a question of where you want the names to be interned. For symbols in a package it is generally very undesirable to intern them in the current package:

    (defpackage foo
      (:export x y z))
    (use-package 'foo)
    

    will fail.

    So then there are two obvious choices:

    • intern things in the keyword package;
    • don't intern them.

    It does not make much difference which you do in practice. Personally I intern package names in the keyword package as I want completion to work on them, but do not intern symbol names, because that seems just to be gratuitous clutter. So my package definitions look like

    (defpackage :foo
      (:use :cl ...)
      (:export #:x #:y ...))