| Allegro CL version 10.1 Unrevised from 10.0 to 10.1. 10.0 version |
This document contains the following sections:
1.0 Packages introductionCommon Lisp allows the use of packages to keep different parts of an application separate, permitting multiple use of symbol names and independent development of different parts of a large program. As delivered, Allegro CL comprises several packages, and users should be aware of which packages are available, which should be used by the user, and which should, in general, be avoided.
Starting in release 6.0, Allegro CL has implemented a hierarchical package naming scheme, allowing the specification of a hierarchy of packages, and the use of relative package specifiers, analogous to relative pathnames. While this facility is an extension to the ANSI spec, programs that do not use hierarchical naming are unaffected (except for the handling of rather unusual, erroneous code). Programs that use it, however, may have to be modified to be portable. See Section 2.0 Hierarchical Packages.
Lisp permits already-defined functions to be redefined dynamically. However, redefining system-defined functions (either from the Common Lisp standard in the common-lisp package or from the Allegro CL implementation, in packages such as excl, system, etc.) is almost always a bad idea. Allegro CL implements a package-locking system which protects symbols in reserved packages from new or changed function definitions. See the discussions under the heading Section 7.0 Package locking and package definition locking below.
The initial package when Allegro CL is started in the :cl-user package when not starting in the IDE and the :cg-user package when starting the IDE. To change the initial package when using the IDE, see the section Note on the initial package in cgide.htm. When not using the IDE, see The package on startup in startup.htm.
Allegro Common Lisp supports fully hierarchical packages. Hierarchical
packages, which are part of many modern languages but not part of ANSI
Common Lisp, are a convenient way to manage namespaces because you
have freedom to choose the name of the root package and then can use
any names you like for the lower-level packages, even names used by
other modules. So you can have your own :test
package
just like every other module.
The hierarchical package implementation affects output
of find-package
(either a direct call or an implicit call triggered by use of a
package qualifier or an argument to in-package or other package-related
function). When given a name containing dots, it tries to resolve the
name in a hierarchical fashion, with respect to the current value
of *package*
. This means that find-package
may have different behavior for names that contain dots depending on
the value of *package*
:
cl-user(9): (defpackage :mypack) #<The mypack package> cl-user(10): (defpackage :mypack.test) #<The mypack.test package> cl-user(11): (find-package :.test) nil cl-user(12): (in-package :mypack) #<The mypack package> mypack(13): (find-package :.test) #<The mypack.test package> mypack(14):
In the example, (find-package :.test)
returns nil
when *package*
is
the :cl-user
package and returns
the :mypack.test
package
when *package*
is the :mypack
package. Note that this is
non-standard behavior. The ANS says that find-package should return the same
value for the same argument regardless of the value
of *package*
.
We have implemented hierarchical packages because of the convenience it offers. Hierarchical packages:
The problem with implementing full hierarchical packages in Common
Lisp is that you need a special character to indicate the hierarchy
levels (we used a period, also called a dot) but this character
is not special in ANSI Common Lisp. Therefore, names
like foo.bar
and .bar
are legal
package names in Common Lisp and have nothing to do with
hierarchy. The hierarchical structure must be superimposed on the
standard Common Lisp package structure.
This issue manifests itself if you have packages with names containing dots, particularly dots at the beginning of the name. It also manifests itself in the treatment of nicknames. We discuss both of these issues below.
Note that we give package names as keywords (:foo
for the foo
package). In modern Lisp, symbol names
are case-sensitive and the :foo
package has name
"foo". In ANSI Lisp, symbol names are case-insensitive and
the :foo
package has name "FOO". In the remainder
of this discussion, we will use lowercase names and the examples are
from a modern implementation (with occasional reminders of the
issue). See case.htm for a discussion of modern and
ANSI Lisps.
Here is the terminology we will use when discussing hierarchical packages:
foo
package, (defpackage :.bar)
creates a package with
name ".bar" (in a modern Lisp, ".BAR" in an ANSI Lisp). It does not
create the package :foo.bar
and (find-package :.bar)
returns
the :.bar
package, not
the foo.bar
package (assuming
the foo.bar
package has not also been created
explicitly).
:.bar
-- or a trailing dot --
:bar.
). For
example foo.bar.baz
. (Multiple consecutive dots --
:bar..baz
-- are also not allowed.) If all the
ancestor packages exist, this package will be relative to them and
using relative name will work when applicable.
:..bar
and .bar.baz
but
not .bar..baz
or .bar.
). When
trying to find the package named by a relative name, the system will
combine the relative name with the current package name as described
below. If that does not find a package, then a package with that
absolute name will be looked for.
(defpackage :foo.bar
(:nicknames :foobar))
is an example.
:flat t
option
to defpackage
or make-package. (defpackage
:foo.bar (:nicknames :foo.b) (:flat t))
is an example.
(defpackage :a.b (:nicknames
:anick.bnick.cnick))
is an example.
(defpackage :foo.bar (:nicknames :baz.b))
is an example. Note the parent package (:foo
in
this case) need not exist when the package is created.
For :flat
t
nicknames, they are used as specified regardless of
whether they contain dots. So (defpackage :foo (:nicknames
:baz.bar) (:flat t))
creates a package with
name :foo
and nickname :baz.bar
and (assuming no other definitions are
relevant) (find-package :bar.baz)
will return the
:foo package while (find-package :.bar)
will return
nil
. Nicknames are further discussed
in Section 2.5 Package nicknames: absolute and relative below.
name1.name2.[...]nameN.name
. The parent of
that package is is name1.name2.[...]nameN
. All
packages name1
, name1.name2
,
etc. through name1.name2.[...]nameN
are ancestor
packages. So for
package :foo.bar.baz
, :foo.bar
is the parent and it and :foo
are ancestors.
[name of
B].[name]
. So :foo.bar.baz
and :foo.bar
are both subpackages
of :foo
.
Hierarchical packages are defined by indicating the hierarchy with dots (periods) in names. For package names, singleton dots can appear separating the various package ancestors, but there cannot be a leading dot, a trailing dot, or any multiple consecutive dots (if any of those appear, the specified name is the absolute name of the package which is not in a hierarchy). For relative names, there must be at least one leading dot but can be any number, and there can be singleton dots elsewhere, but no trailing dot.
The problem is dots are not special characters and so Common Lisp
allows any number of dots in package names. However, dots do matter in
the hierarchical package implementation. As said above, hierarchical
packages affect what package is found by (find-package
:<name>)
directly or implicitly with
<name>::<symbol>
and
in package arguments to operators. Mixing
packages with names that beging with a dot with relative package names
can result in unexpected results because of shadowing and name
conflicts. Here is an example:
;; We define package :luser, :.zoo, and :luser.zoo. ;; Except when *package* is the :luser package, ;; (find-package :.zoo) returns the :.zoo package. ;; When *package* is the :luser package, (find-package :.zoo) ;; returns the :luser.zoo package and find-package will not ;; return the :.zoo package for any argument value. ;; cl-user(1): (defpackage :luser) #<The luser package> cl-user(2): (defpackage :.zoo) #<The .zoo package> cl-user(3): (defpackage :luser.zoo) #<The luser.zoo package> cl-user(4): (find-package :.zoo) #<The .zoo package> cl-user(5): :pa luser luser(6): (find-package :.zoo) #<The luser.zoo package> luser(7): (defpackage :cl-user.zoo) #<The cl-user.zoo package> luser(8): (find-package :.zoo) #<The luser.zoo package> luser(9): :pa cl-user cl-user(10): (find-package :.zoo) #<The cl-user.zoo package> cl-user(11): (defpackage :other) #<The other package> cl-user(12): :pa other other(13): (find-package :.zoo) #<The .zoo package> other(14):
You might think you should avoid package names beginning with a dot
entirely, but one can imagine scenarios where such names might be
useful. Suppose in your hierarchy, every package has a subpackage with
relative name :.test
. You may wish to also create a
:.test
package (with (defpackage
:.test)
) so (find-package :.test)
will
never return nil
regardless of the value of
*package*
. But
outside of that case, leading dots in package names should likely be
avoided.
Because a dot (period) delimits levels of the package hierarchy, a trailing dot does not make sense in a hierarchical scheme: it should be followed by a name lower in the hierarchy but there is no name.
Therefore, package names or nicknames ending with one or more dots are considered flat names (not hierarchical names).
A package name containing one or more single dots (but no multiple
consecutive dots, no leading dot, and no trailing dot) is potentially
a hierarchical package. So (defpackage
:foo.bar.baz)
is potentially a hierarchical package, with
name "foo.bar.baz" and potential ancestors the :foo
package and the
:foo.bar
package, if they exists. When
the :foo
package and
the :foo.bar
packages are defined, then the
:foo.bar.baz
package becomes a hierarchical package
and rules for resolving relative names will apply. This rules are
described in Section 2.6 Resolving relative package names
below.
To repeat and important point: a package become hierarchical when all its potential ancestor packages exist. The package will be immediately hierarchical if they already exist when the package is created. It becomes hierarchical later if the ancestor packages do not exist but are created later.
Package nicknames are specified by the :nicknames
option to defpackage/argument
to make-package. The
nickname will be hierarchical if it has the same number of dots, the
same parent (everything up to the last dot), and is not specified as
flat. In that case, relative names can be used when the current
package is the parent package (or one of its ancestors). (Nicknames
ending in a dot are an anomaly discussed
in Section 2.8 Hierarchical package anomalies below.) Nicknames
without dots, with a different number of dots, or with a different
parent are absolute (or flat) nicknames and can be used to find the
package regardless of the value of *package*
.
Consider the following example:
cl-user(2): (defpackage :newpack) #<The newpack package> cl-user(3): (defpackage :newpack.test (:nicknames :mytest :different-parent.nopt :a..lot...of...dots...newpt :newpack.npt)) #<The newpack.test package> ;; The full nicknames all work, flat or relative: cl-user(4): (find-package :mytest) #<The newpack.test package> cl-user(5): (find-package :different-parent.npt) #<The newpack.test package> cl-user(6): (find-package :a..lot...of...dots...newpt) #<The newpack.test package> cl-user(7): (find-package :newpack.npt) #<The newpack.test package> cl-user(8): (find-package :.npt) ;; relative name but not in the right package to resolve ;; the relative name. See below when *package* is ;; the :newpack package. nil cl-user(9): (in-package :newpack) #<The newpack package> ;; The possible relative nicknames are :.nopt, :.newpt, and :.npt ;; from nicknames :different-parent.nopt, :a..lot...of...dots...newpt, ;; and :newpack.npt. But only the last works when in the :newpack ;; package. All the rest have something which disqualifies them. newpack(10): (in-package :newpack) #<The newpack.test package> newpack(11): (find-package :.nopt) ;; :different-parent.nopt has the right number of dots but ;; a different parent. nil newpack(12): (find-package :.newpt) ;; :a..lot...of...dots...newpt has too many dots. nil newpack(13): (find-package :.npt) ;; This one is a proper relative package nickname. #<The newpack.test package> newpack(14): (find-package :.newpt) nil newpack(11): (find-package :newpack.npt) ;; relative nicknames only work as relative names. Their full ;; name is not a nickname. nil newpack(15):
If the :flat
option to defpackage/keyword argument to
make-package is
specified true, the name is stored in the flat hashtable rather than as part of a hierarchy and all nicknames defined are made absolute nicknames
whether or not they contain dots (see
Extensions to cl:make-package,
cl:disassemble, cl:truename, cl:probe-file, cl:open,
cl:apropos and cl:defpackage and cl:in-package, both in
implementation.htm, for more information on
extensions to defpackage and make-package.)
The fact that the name is stored in the flat hashtable is an
implementation detail which may have no visible consequences to the
user (so (defpackage :foo)
and (defpackage
:foo.bar (:flat t))
ctreates
packages :foo
and :foo.bar
, and
even though :foo.bar
is
flat, (find-package :.bar)
when *package*
is the
:foo
package returns
the :foo.bar
package). The consequences to
nicknames is, howver, significant, as we discuss next.
In this example, we specify nicknames containing dots but also specify
:flat t
. As a result, all the nicknames are
absolute nicknames and none work as relative nicknames.
cl-user(53): (defpackage :pack1) #<The pack1 package> cl-user(54): (defpackage :pack1.flatpack (:nicknames :.fpk :a..lot.of..dots :.pack1.gp :flatpk) (:flat t)) #<The pack1.flatpack package> cl-user(55): (find-package :.fpk) ;; absolute nickname, not relative #<The pack1.flatpack package> cl-user(56): (find-package :a..lot.of..dots) ;; absolute here too #<The pack1.flatpack package> cl-user(57): (find-package :flatpk) ;; this one is always absolute #<The pack1.flatpack package> cl-user(58): (in-package :pack1) #<The pack1 package> pack1(59): (find-package :.gp) ;; Without :flat t, this would work ;; as a relative nickname nil pack1(60): (find-package :.fpk) ;; this is an absolute nickname and ;; so works (it just looks like a relative ;; nickname) #<The pack1.flatpack package> pack1(61): (find-package :a..lot.of..dots) ;; absolute nickname #<The pack1.flatpack package> pack1(62):
When find-package is
passed an actual package name or an absolute nickname, the associated
package is returned (except perhaps when the name looks like a
relative name,
see Section 2.8 Hierarchical package anomalies). When it is passed
a relative name, it tries to resolve that name with respect to the
current package (the value of *package*
and returns the package
found, if any. find-package tries to resolve relative
names with *package*
before it looks for an
absolute name that resembles the relative name but it will find the
absolute name if there is no relative name resolution.
A relative package name is a name that starts with any number
of dots (but at least one) and may contain additional single dots, but
does not end with a dot and contains no additional multiple
consecutive dots. So
:.foo
, :...foo
,
:.foo.bar
, and :..foo.bar.baz
are all relative names but :[any character beside a
dot][pehaps more characters]
, :p.foo
,
:..foo..bar
, and :.foo.
are not.
When there are multiple dots at the beginning, they are treated
analogously with initial dots in pathnames, with a single dot meaning
the current package, two dots meaning the parent of the current
package, and more than two meaning ancestors of the current package
further back. (find-package :.)
always returns the
current package. (find-package :..)
returns the
parent of the current package, if there is one (and signals an error
if there is not).
Here are multiple examples of resolving relative pathnames. Note that resolving relative package names is done by explicit calls to find-package and also by implicit calls, such as finding the package indicated by a package qualifier to a symbol or finding the package in a call to in-package.
In these examples, we assum that packages
named mypack
,
mypack.foo
, mypack.foo.bar
,
mypack.foo.baz
, mypack.bar
,
mypack.bar.baz
, foo
, and
foo.bar
, have all been created:
relative name | current package | absolute name of referenced package |
---|---|---|
foo |
any | foo |
foo.bar |
any | foo.bar |
.foo |
mypack |
mypack.foo |
.foo.bar |
mypack |
mypack.foo.bar |
..foo |
mypack.bar |
mypack.foo |
..foo.baz |
mypack.bar |
mypack.foo.baz |
...foo |
mypack.bar.baz |
mypack.foo |
. |
mypack.bar.baz |
mypack.bar.baz |
.. |
mypack.bar.baz |
mypack.bar |
... |
mypack.bar.baz |
mypack |
Because Allegro CL implements true hierarchical packages, relative nicknames can be used in place of relative names at any level, and absolute nicknames can also be used, as the following example shows:
cl-user(78): (defpackage :zpack (:nicknames :zpa)) #<The zpack package> cl-user(79): (defpackage :zpack.foo (:nicknames :.zfo :zop)) #<The zpack.foo package> cl-user(80): (defpackage :zpack.foo.bar) #<The zpack.foo.bar package> cl-user(81): (find-package :zpa.foo) #<The zpack.foo package> cl-user(82): (find-package :zpa.zfo) #<The zpack.foo package> cl-user(83): (find-package :zpack.zop.bar) ;; zop is an absolute nickname nil cl-user(84): (find-package :zop.bar) ;; so this works #<The zpack.foo.bar package> cl-user(85): (in-package :zpack) #<The zpack package> zpa(86): (find-package :.zop) ;; again, an absolute nickname nil zpa(87): (find-package :.zfo) #<The zpack.foo package> zpa(90): (in-package :zpack.foo.bar) #<The zpack.foo.bar package> zpack.foo.bar(91): (find-package :.) #<The zpack.foo.bar package> zpack.foo.bar(92): (find-package :..) #<The zpack.foo package> zpack.foo.bar(93): (find-package :...) #<The zpack package> zpack.foo.bar(94): (find-package :...foo) #<The zpack.foo package> zpack.foo.bar(95):
Because implementing hierarchical packages makes dots into special characters, you may see behavior which is unexpected or (at first) unintuitive (and also not what standard Common Lisp would do). This has been true since partial hierarchical packages were first introduced and remains true now that fully hierarchical packages have been implemented.
;; We define package :luser, :.zoo, and :luser.zoo. ;; Except when *package* is the :luser package, ;; (find-package :.zoo) returns the :.zoo package. ;; When *package* is the :luser package, (find-package :.zoo) ;; returns the :luser.zoo package and find-package will not ;; return the :.zoo package for any argument value. ;; cl-user(1): (defpackage :luser) #<The luser package> cl-user(2): (defpackage :.zoo) #<The .zoo package> cl-user(3): (defpackage :luser.zoo) #<The luser.zoo package> cl-user(4): (find-package :.zoo) #<The .zoo package> cl-user(5): :pa luser luser(6): (find-package :.zoo) #<The luser.zoo package> luser(7): (defpackage :cl-user.zoo) #<The cl-user.zoo package> luser(8): (find-package :.zoo) #<The luser.zoo package> luser(9): :pa cl-user cl-user(10): (find-package :.zoo) #<The cl-user.zoo package> cl-user(11): (defpackage :other) #<The other package> cl-user(12): :pa other other(13): (find-package :.zoo) #<The .zoo package> other(14):
:flat t
in the defpackage or make-package form (see
Extensions to cl:make-package,
cl:disassemble, cl:truename, cl:probe-file, cl:open,
cl:apropos and cl:defpackage and cl:in-package, both in
implementation.htm, for more information on
extensions to defpackage and make-package), specifying a nickname
ending in a dot (like (:nicknames :foo.bar.baz.)
)
will follow the relative nickname rule of ignoring everything up to
the last dot, and so the nickname will be "." which in any case names
the current package. In some cases, you may get an error.
nil
if the string obtained from its
argument does not name a package. However, if passed a name beginning
with more than one dots, it tries to find the parent of the current
package, and (if necessary) the parent of that package, and so on
until all dots are resolved. If at any point there is no parent, then
an error is signaled. So:
zpack.foo.bar(106): *package* #<The zpack.foo.bar package> zpack.foo.bar(107): (find-package :.) #<The zpack.foo.bar package> zpack.foo.bar(108): (find-package :..) #<The zpack.foo package> zpack.foo.bar(109): (find-package :...) #<The zpack package> zpack.foo.bar(110): (find-package :....) Error: The parent of package #<The zpack package> does not exist.
BETA NOTE: The correct behavior for these cases is still under review. Behavior may change in the final release.
Allegro CL typically puts newly created packages under the following top-level names:
The use of these top-level names as packages in applications might run into problems with Allegro CL. Note that all current package names (such as excl, system etc.) will also be used.
To facilitate using hierarchical packages, there are the functions package-parent and package-children.
Package-local nicknames were implemented by a patch for Allegro CL 10.1 released in August, 2019. This document assumes that patch has been applied. See sys:update-allegro for information on applying patches.
The Allegro CL hierarchical package feature (described above in the
section Section 2.0 Hierarchical Packages) allows packages
to be arranged in hierachies so that programmers may use shorter
labels for packages when the current value of *package*
is a package higher in the
hierarchy. However the shorter name needed to start with one of more
dots.
But another way to define local nickanmes does away with leading
dots. It allows a package to have a specified nickname in a specified
package (called the housing package). When the housing package
is the current package, that is the value of *package*
, the local nickname
applies. Local nicknames can be specified when a housing package is
created with defpackage or make-package.
(See Extensions to
cl:make-package and cl:defpackage and cl:in-package
in implementation.htm.) Local nicknames can also be
added with the function add-package-local-nickname.
Here is an example:
cl-user(9): (defpackage :bar (:intern #:x)) #<The bar package> ;; Using the new :LOCAL-NICKNAMES option, we specify that when the current ;; package is :MYPACK, :B is a nickname of the :BAR package (the value of ;; :LOCAL-NICKNAMES is a list (NICKNAME PACKAGE-NAME)) cl-user(10): (defpackage :mypack (:use :cl :excl) (:local-nicknames (:b :bar))) #<The mypack package> ;; While the current package is :CL-USER, there is no package ;; named :B: cl-user(11): (find-package :b ) nil cl-user(12): (in-package :mypack) #<The mypack package> ;; BUT when the current package is :MYPACK, :B is a nickname of the ;; :BAR package: mypack(13): (find-package :b ) #<The bar package> mypack(14): (eq 'b::x 'bar::x) t
Even though you an get similar behavior with hierarchical packages, it
is not the same. If you are importing code from elsewhere or using
Lisp libraries from elsewhere, redefining packages so they are
hierarchical may not be easy and does cause your code to diverge from
the code base. But with package-local nicknames, you can define a
nickname and use it when the housing package is the value of
*package*
. Local nicknames are a
feature of the definition of the housing package. The definition of
the package given a local nickname does not define or even name the
local nickname (except perhaps by chance: a package definition may
specify a nickname for a package which happens to be the same as a
local nickname but in that case, the local nickname is redundant.)
The local nickname can be any name except the name or nickname of the
housing package, any name for the common-lisp
package (including a nickname like cl
and lisp
), and any name for
the keyword
package (again including nicknames
although none are defined in Allegro CL initially).
It is important to understand that if a local package nickname is the same
as the name or nickname of another package, it shadows that name for
other package. So if a package has name :foo
and no
nicknames, and :foo
is selected as a local package
nickname for some other package, say the :bar
package, in the housing package :mypack
, then when
:mypack
is the current
package, :foo
always points to
package :bar
, so (find-package
:foo)
returns the :bar
package
and foo::x
names the symbol x
in
the :bar
package. See the example below
under Losing print/read consistency.
The following functions have been defined to support local package nicknames:
The existing function package-alternate-name has been modified to
return a local nickname rather than the global alternate name for
packages which have local nicknames in the package that is the current
package. The effect of a non-nil
value for
the variable
*print-alternate-package-name*
has also
been changed to work with package local nicknames.
Here are some example using package local nicknames:
;; We define a package without nicknames (in real life, this ;; might be a package from imported software): (defpackage :valuetest (:use :excl :cl)) ;; Here is another package with nickname :v created by another ;; developer on a project: (defpackage :validate (:use :cl :excl) (:nicknames :v)) ;; And here is the package you are working with, :mypack. You specify ;; :v as the local nickname for the :valuetest package and so ;; :v is not the nickname for the :validate package when *package* ;; is the :mypack package: (defpackage :mypack (:use :cl :excl) (:local-nicknames (:v :valuetest))) ;; Here is a transcript of some interactions: ;; :v is the nickname for the :validate package unless the value ;; of *package* is the :valuetest package: cl-user(9): (find-package :v) #<The validate package> ;; When *print-alternate-package-name* is nil, the package name ;; is used by the printer: cl-user(10): (setq *print-alternate-package-name* nil) nil cl-user(11): 'v::x validate::x ;; When *print-alternate-package-name* is non-nil, the first ;; local nickname is used if there is one, otherwise the first ;; actual nickname: cl-user(12): (setq *print-alternate-package-name* t) t cl-user(13): 'v::x v::x cl-user(14): (package-nicknames :v) ("v") cl-user(15): (package-nicknames :validate) ("v") cl-user(16): (package-nicknames :valuetest) nil ;; Now we make *package* be the :mypack package. There :v is ;; the local nickname of the :valuetesy package and that shadows ;; the use of :v as the nickname of the :validate package: cl-user(17): (in-package :mypack) #<The mypack package> mypack(18): (find-package :v) #<The valuetest package> ;; The package-nicknames function only returns actual nickname, not ;; local nicknames: mypack(19): (package-nicknames :valuetest) nil mypack(20): (package-nicknames :validate) ("v") ;; *print-alternate-package-name*, when nil, causes the full package ;; name of the local nickname to be used: mypack(21): (setq *print-alternate-package-name* nil) nil mypack(22): 'v::x valuetest::x mypack(23): (setq *print-alternate-package-name* t) t mypack(24): 'v::x v::x mypack(25):
Package-local nicknames may be the same as the names or nicknames of
other packages. When this happens and the value
of *package*
is
the relevant housing package, and *print-alternate-package-name*
is true, when
the printer prints a package-qualified symbol it may use a nickname
which does not name the package
when *package*
has a different value. We see this
in the examples above. valuetest::x
prints
as v::x
when *package*
is the
:mypack
package, but
reading v::x
when *package*
is
:cl-user
results in validate::x
.
That is all to be expected. The same thing happens with hierarchical
packages. :.test
refers
to :pack1.pack2.test
when *package*
is :pack1
or
:pack1.pack2
but refers
to opack.test
when *package*
is
:opack
.
But things get more complicated when either of these hold:
*print-alternate-package-name*
is nil
and a local package nickname is the
same as another package's name.
*print-alternate-package-name*
is true and the
name and every nickname of another package are all also local package
nicknames.
Here are some examples:
cl-user(4): (defpackage :foo (:nicknames :f1)) #<The foo package> cl-user(5): (defpackage :fire) #<The fire package> cl-user(6): (defpackage :bar (:nicknames :b1)) #<The bar package> cl-user(7): (defpackage :baz) #<The baz package> cl-user(8): (defpackage :mypack1 (:use :excl :cl) (:local-nicknames (:foo :fire) (:bar :baz) (:b1 :baz))) #<The mypack1 package> ;; The values of these variable are the symbol X in the package ;; which is part of the variable name. They are all in the CL-USER ;; package. cl-user(11): (defvar *foo-x* 'foo::x) *foo-x* cl-user(12): (defvar *bar-x* 'bar::x) *bar-x* cl-user(13): (defvar *baz-x* 'baz-x) *baz-x* cl-user(14): (defvar *fire-x* 'fire::x) *fire-x* ;; Now we make the current package MYPACK1, which has various ;; local nicknames: cl-user(14): (in-package :mypack1) #<The mypack1 package> ;; FOO is the local nickname of the FIRE package: mypack1(15): (find-package :foo) #<The fire package> ;; Therefore FOO::X and FIRE::X are EQ: mypack1(16): (eq 'foo::x 'fire::x) t ;; When *PRINT-ALTERNATE-PACKAGE-NAME* is NIL, the printer uses the ;; package name regardless of local nicknames: mypack1(17): (setq *print-alternate-package-name* nil) nil ;; So it prints FOO::X for a symbol in the FOO package even though FOO ;; is the nickname of the FIRE package: mypack1(18): user::*foo-x* foo::x mypack1(19): user::*fire-x* fire::x mypack1(20): (eq * **) nil ;; When *PRINT-ALTERNATE-PACKAGE-NAME* is true, the printer uses the ;; local nickname: mypack1(21): (setq *print-alternate-package-name* t) t ;; The local nickname of the BAZ package is BAR, so BAZ::X is printed ;; BAR::X: mypack1(22): user::*baz-x* bar::x ;; The nickname for th BAR package (B1) is shadowed so the printer must ;; use the package name even though it is also shadowed: mypack1(23): user::*bar-x* bar::x mypack1(24): user::*baz-x* bar::x ;; The two symbols print the same but are not the same symbol: mypack1(25): (eq * **) nil
So print/read consistency can be lost even when the value
of *package*
does not change. This is a consequence of allowing local nicknames to
be the same as package names and (global) package nicknames. Now local
package nicknames are a tool to assist one developer among many to use
convenient local nicknames in code in that developer's own
package. Shadowing names and nicknames of other packages is not the
intention but presumably only happens when the other package is not
relevant for current development.
In addition to the hierarchical packages named in Section 2.9 Package prefixes reserved by Allegro CL, the following packages used by Allegro CL are of direct importance to the user. Note that all nicknames are not listed in every case. Use package-nicknames applied to a package to see the complete list. The first nickname listed in each case is the principal nickname.
Some of these packages may not exist in a standard Allegro CL image until a fasl file containing the functionality associated with the package is loaded. In many cases, the loading is automatic when the package is referenced. Thus
(find-package :flavors)
causes flavors.fasl to be loaded from the bundle. The cltl-1 module is not atoloaded.
Name |
Some nicknames |
Brief Description |
Locked? |
Notes |
acl-socket |
Socket interface functionality. See socket.htm. | No | Autoloaded | |
aclwin |
aclwin302 | Functionality from Allegro CL 3.0.2 kept in 6.x for backward compatibility. | Yes | Exists in Windows and Unix. In Unix, do (require :aclwin) In Unix, symbols having to do with graphics have no function definition. Functionality that is Windows-specific generates an error when called in Unix. |
clos |
the MOP extension to CLOS (CLOS functionality is in common-lisp). | Yes | Always present in an image. | |
cltl1 |
Some symbols removed some functionality redefined from the Common Lisp standard by X3J13. | No | Functionality named by symbols in this package is out of date and use should be avoided. Not autoloaded. | |
common-graphics |
cg | Common Graphics windows functionality. | Yes | Windows only. Always present in an image with the IDE. |
common-graphics-user |
cg-user | User environment in the IDE | No | Windows only. Uses aclwin, excl, cg, cl, ide. Always present in an image with the IDE. |
common-lisp |
cl | Standard CL symbols. | Yes | Always present in an image. |
common-lisp-user |
cl-user user |
User environment. | No | Uses cl and excl. Always present in an image. |
compiler |
comp | Symbols naming functionality associated with the compiler. See compiling.htm. | Yes | Autoloaded. |
cross-reference |
xref | Symbols naming functionality associated with the cross referencer. See cross-reference.htm. | Yes | Autoloaded. |
dde |
Symbols naming functionality associated with the DDE interface on Windows. See dde.htm | No | Autoloaded. | |
defsystem |
Symbols naming functionality associated with defsystem. See defsystem.htm | Yes | Autoloaded. | |
debugger |
db | Symbols naming functionality associated with the debugger. See debugging.htm. | Yes | Autoloaded. |
excl |
excl | General extensions to Common Lisp | Yes | Always present in an image. |
foreign-functions |
ff | Symbols naming functionality associated with the foreign functions facility. See foreign-functions.htm. | Yes | Autoloaded. |
garbage |
Package for compiler labels and some CLOS names. | No | Always present in an image. | |
ide |
Integrated Development Environment functionality. | Yes | Windows only. Always present in an image with the IDE. | |
inspect |
Symbols naming functionality associated with the inspector. See inspector.htm. | Yes | Autoloaded. | |
keyword |
Standard CL package. | No | Always present in an image. | |
multiprocessing |
Symbols naming functionality associated with multiprocessing. See multiprocessing.htm. | Yes | Autoloaded. | |
profiler |
prof | Symbols naming functionality associated with the runtime analyzer. See runtime-analyzer.htm. | Yes | Autoloaded. |
system |
sys, si | System functionality and internals. | Yes | Always present in an image. |
top-level |
tpl | Symbols naming functionality associated with the top level. See top-level.htm. | Yes | Always present in an image. |
When you start up Allegro CL on UNIX or without the Integrated
Development Environment on Windows, you are in the
common-lisp-user
package. At the start, there are
no symbols in the common-lisp-user
package, but the
common-lisp
and excl
packages
are used, so external symbols from those packages are available to the
user
package. When you start the Integrated
Development Environment (Windows only) you are in the
common-graphics-user
package.
The common-lisp
package contains only those symbols
specified in the ANSI CL specification. Some of the capabilities of
standard Common Lisp functions have been extended, but they can all be
used in the way specified in ANSI CL. The extensions are not portable,
of course. See implementation.htm for
more information on extensions to standard Common Lisp
functionality.
With that caveat, if you use the common-lisp package only, you will have portable code that can with greatest ease be ported to Common Lisp systems other than Allegro CL.
A number of symbols were removed from the Common Lisp standard by
the X3J13 committee. We have maintained many of these symbols in the
cltl1
package, for the purpose of providing
backward compatibility.
The excl
and system
packages
contain many of the extensions in Allegro CL. Two packages in earlier
versions on UNIX (4.3.x and earlier), franz
and
stream
, have been merged with excl
starting in version 5.0. Both stream
and
franz
are nicknames of
excl
. excl
is also the principal
nickname of the excl
package to ensure that name is
used when *print-nickname*
is true.
The top-level
package contains symbols used by
the top level. Note that some of these symbols have the same names as
symbols in the common-lisp
package (for example,
*print-level*
and
*print-length*
).
Therefore, we recommend that a package using the
common-lisp
package not use (in the sense of use-package) the
top-level
package.
Packages can have (usually shorter) nicknames, which can be used in place of the full names. Symbols unavailable in the current package are printed (during, e.g., tracing) with package qualifiers.
Allegro CL has permitted using the principal nickname (defined to be
first in the nickname list) instead of the actual name by setting the
value of the variable *print-nickname*
to true. This worked well for
most things but had severe limitations. In particular, the only way to
use the actual package name when *print-nickname*
was to have no nickname. But
sometimes you want nicknames and you want to use the actual name
instead of the nickname (actual names may not also be a nickname).
Allegro CL now supports an alternate name. This must be the package name or one of the nicknames. The laternate name is defined when a package is created with defpackage or make-package.
When *print-alternate-package-name*
is true, the
alternate name will be used. If the alternate name is not specified
and *print-alternate-package-name*
, the principal
nickname is used (that is, the first nickname is the list returned
by package-nicknames). If the package has
no nicknames, the package-name is used.
The alternate package name can be specified by the
new :alternate-name
option to defpackage and keyword argument to
make-package. See
Extensions to cl:make-package,
cl:disassemble, cl:truename, cl:probe-file, cl:open,
cl:apropos and cl:defpackage and cl:in-package, both in
implementation.htm, for more information on
extensions to defpackage and make-package.
The alternate name can be accessed by the package-alternate-name function. If no alternate name is specified, the altername name is the first in the list of nicknames or the package name if there are no nicknames. The alternate, if explicitly specified, must be either the package name or one of the nicknames.
Allegro CL allows you to specify whether you want the alternate
package name or the package name as the qualifier. The following
variable *print-alternate-package-name*
controls which
is used. Note that certain utilities (e.g. apropos and the debugger) bind this variable to
true and so always use the alternate name.
The principal nickname of some of the packages of interest to users
are listed next (nil
means no defined
nicknames). The alternate name is in bold.
Table 2: Package Nicknames |
||
Package name |
Principal Nickname ( |
Other Nickname (some nicknames may not be listed) |
common-lisp |
cl |
lisp |
clos |
nil |
|
excl |
nil |
|
system |
sys |
si |
common-lisp-user |
cl-user |
user |
debugger |
debug |
db |
inspect |
nil |
|
compiler |
comp |
|
flavors |
fla |
|
foreign-functions |
ff |
|
multiprocessing |
mp |
|
top-level |
tpl |
|
defsystem |
defsys |
ds |
cross-reference |
xref |
Package nicknames can be found with the Common Lisp function
package-nicknames, which
returns a list of the nicknames of its argument, with the principal
one first. Sometimes, you may wish to use a nickname of an Allegro CL
package as the name of your own package. (E.g. some users would like
to have their own package named db
, perhaps for
database functionality, but db
is a nickname of the
debugger
package.) You can change the nicknames of
a package with rename-package.
You must do it in a without-package-locks form, however, because
of package locking described just below.
Packages have two kinds of locks as an extension in Allegro CL. The package-lock protects a package from changes in its structure (its use list, its exported symbols, etc.). The package-definition-lock protects the symbols in the package from new or changed uses as the name of a function, macro, structure, or type.
Tracing and advice are not affected by either type of package locking.
When the function package-lock returns true when applied to a package, we say the package is package-locked. When a package is package-locked, the system will signal an error of type package-locked-error when code is executed that tries to:
The list is exhaustive. Note that intern and delete-package cannot
signal a package-locked-error. The function package-lock applied to a package object (but
not a symbol or string naming a package) returns true if the package
is locked and returns nil
if it is not
locked. Setf can be used with package-lock to lock or unlock a package.
A package is package-definition-locked if the function package-definition-lock (whose argument must be a package object, not a package name) returns true when applied to the package. When a package is package-definition-locked, the system will signal an error when code is executed that attempts any of the following actions on a symbol homed in the package:
Function names that are lists are also protected if the important
symbol (usually the cadr, e.g. border in (setf
border)
) in the list is in the definition-locked package. We
repeat here the definition of package-definition-lock because it describes
how the lock can be circumvented.
package-definition-lock
Arguments: package
Returns
t
ornil
as package is or is not definition-locked. package must be a package object (it cannot be a symbol or a string). setf may be used with this function to definition-lock or unlock a package.Even if a package is package-definition-locked, no error will be signaled when
- the value of
*enable-package-locked-errors*
isnil
;- the violation is dynamically inside the body of a call to the macro without-package-locks;
- the list returned by applying package-implementation-packages to the value of
*package*
contains the home package of the symbol being operated on. Implementation packages are defined just below. Note that unless you have specified a list of implementation packages for a package that does not include the package itself (which would be unusual), no error will be signaled when*package*
is the home package of the symbol being operated on. Also, no error is signaled if the value of*package*
is the home package of the symbol being operated on regardless of the contents of package-implementation-packages.If a violation is encountered while compiling a file, a warning is signaled rather than an error. If the resulting fasl file is loaded, an error will then be signaled.
Allegro CL allows a package to have a list of associated packages
(called implementation packages). No warning or error will be
signaled for a definition or redefinition in one package when the
value of *package*
is an
implementation package of that package. Both defpackage and make-package have been extended to accept an
implementation-packages keyword
argument and the setfable function package-implementation-packages accesses that
list of packages.
The value of the implementation-packages argument
to make-package should be a
list of strings naming packages. The defpackage form should contain a subform which
is a list whose first element is
:implementation-packages
and whose remaining
elements are strings naming the desired packages (as shown in the
example below). When unspecified, the list of implementation packages
defaults to a list containing the string naming the package being
defined. The implementation-packages argument is
not standard Common Lisp. You may wish to conditionalize it in
portable code, as shown next.
(defpackage :mypack #+allegro (:implementation-packages "MYPACK" "MYPACK-2") ; other options as desired )
The :implementation-packages
option will only be
read by Allegro CL. Note that since we specified a value, we had to
include "MYPACK" as well as "MYPACK-2" in order to
allow symbols whose home package is mypack
to be
redefined without warning or error while the value of *package*
is the
mypack
package.
Note that implementation packages protects against warnings and errors for package definition locks only. Package locks (the distinction is described above) are not affected.
Here is an example. Suppose we define two packages: foo and
bar. "BAR" is on the
:implementation-packages
list for
foo, but "FOO" is not on the
:implementation-packages
list for
bar
. Both packages are definition-locked.
(defpackage :foo (:implementation-packages "FOO" "BAR")) (defpackage :bar) (setf (package-definition-lock (find-package :foo)) t) (setf (package-definition-lock (find-package :bar)) t)
Consider the following two files. The first starts with
(in-package :bar)
and defines a function on
foo::mysym. The second starts with
(in-package :foo)
and defines a function on
bar::my-other-sym. Compiling or
loading the first file signals no warning or error, since the bar
package is an implementation package for the foo package. The second
signals a warning on compilation and an error on loading because the
foo
package is not an implementation package for the
bar
package.
;; File # 1 ;; Compiling or loading this file will not signal a warning ;; (for compilation) ;; or an error (for loading) even if the FOO package is ;; definition locked, ;; because the BAR package is an implementation package of ;; the FOO package. (in-package :bar) (defun foo::mysym (a b ) (+ a b)) ;; File # 2 ;; Compiling or loading this file will signal a warning ;; (for compilation) ;; or an error (for loading) if the BAR package is definition ;; locked, because ;; the FOO package is not an implementation package ;; of the BAR package. (in-package :foo) (defun bar::my-other-sym (c) (sqrt c))
The following script shows what happens when you try to perform a
protected action on a package-locked package. Here we try to export
the symbol excl::*debug-enclose-printer-errors*
from the excl
package.
USER(3): (export 'excl:: *debug-enclose-printer-errors* (find-package :excl)) Error: #<The EXCL package> is locked against changes by EXPORT. [condition type: PACKAGE-LOCKED-ERROR] Restart actions (select using :continue): 0: Allow EXPORT to modify #<The EXCL package>. [1c] USER(4):
The next script shows what happens when you try to define a
function on a symbol in a package-definition-locked package. We try to
define a function on the symbol
excl:*read-init-files*
. We chose this admittedly
strange example to make clear that a symbol need not already have a
function definition (the symbol in question does not) in order for an
error to be signaled.
USER(18): (defun excl:*read-init-files* nil nil) Error: Attempt to make a FUNCTION definition for the name EXCL:*READ-INIT-FILES*. This name is in the EXCL package and defining it is a violation for portable programs. The package EXCL has PACKAGE-LOCK-DEFINITIONS set, which causes the system to check for this violation. [condition type: PACKAGE-LOCKED-ERROR] Restart actions (select using :continue): 0: Set the FUNCTION definition of the name EXCL:*READ-INIT-FILES* anyway. [1c] USER(19):
In each case, the error has condition type package-locked-error and in each case the error is continuable. By entering :continue 0, the requested action (exporting the symbol or defining the function) will take place.
Note however that package locking is in place for a reason: changing a system-supplied package or defining (or particularly redefining) a function on a symbol in a system-supplied package can cause Lisp to fail because assumptions about the package are violated.
Obviously there are times when changing a package or the definition on a symbol is the right thing to do. If, for example, we instruct you to make some change (say, export a symbol accidentally left off an export list), we are guaranteeing that doing so will not have adverse consequences.
The variable *enable-package-locked-errors*
and macro
without-package-locks can be
used to prevent package-locked-errors (of either type -- ordinary
locks and definition locks) without actually unlocking a package.
When *enable-package-locked-errors*
is true,
executing code that violates package-locking or
package-definition-locking will signal errors and compiling such code
will signal warnings as described above. When it is nil
, such code will execute without
package-locked-errors or compile-time warnings.
The macro without-package-locks, which takes one or more
forms as its arguments, evaluates those forms with *enable-package-locked-errors*
bound to nil
.
For symbols in the common-lisp
package, all of
the actions prevented by package locking and package definition
locking are explicitly restricted by the ANSI specification (see
sections 11.1.2.1.2 and 11.1.2.1.2.1). The
common-lisp
package is locked and definition locked
as are a number of Allegro CL packages, including
aclmop aclwin (Windows only) clos cltl1 common-graphics (Windows only) common-lisp compiler cross-reference debugger defsystem excl excl.scm foreign-functions inspect lep multiprocessing profiler system top-level
For the common-lisp
package, the restrictions of both
package-locks and package-lock-definitions locks are compliant with
the ANSI standard. Other system-provided packages in Allegro CL are
also locked, for the same reasons that the
common-lisp
package is locked.
Writers of application packages may want to lock their packages as
well, especially if the package may be used by other packages written
later. Package locks can detect inadvertent name collisions before
they cause program failures. The following forms will package-lock and
package-definition-lock the package foo
. The same
forms, with nil
instead of t
, unlock the package.
(setf (excl:package-lock (find-package :foo)) t) (setf (excl:package-definition-lock (find-package :foo)) t)
Copyright (c) 1998-2022, Franz Inc. Lafayette, CA., USA. All rights reserved.
This page was not revised from the 10.0 page.
Created 2019.8.20.
| Allegro CL version 10.1 Unrevised from 10.0 to 10.1. 10.0 version |