ToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.0
Significantly revised from 9.0.
9.0 version

Packages

This document contains the following sections:

1.0 Packages introduction
   1.1 The current package on startup
2.0 Hierarchical Packages
   2.1 Hierarchical Package Terminology
   2.2 The problem with dots 1: find-package with names that begin with dots
   2.3 The problem with dots 2: names and nicknames that end with dots
   2.4 Defining hierarchical packages
   2.5 Package nicknames: absolute and relative
      2.5.1 Names and Nicknames created with :flat t
   2.6 Resolving relative package names
   2.7 Hierarchical package specified with nicknames
   2.8 Hierarchical package anomalies
   2.9 Package prefixes reserved by Allegro CL
   2.10 Functions for hierarchical packages
3.0 Packages in Allegro CL
4.0 Notes on specific packages
5.0 Package nicknames and alternate names
6.0 Package locking and package definition locking
   6.1 Package locking
   6.2 Package definition locking
   6.3 Implementation packages
   6.4 Package locked errors
   6.5 Locally circumventing package locked errors
   6.6 The packages locked by default
   6.7 Justification for package locking


1.0 Packages introduction

Common 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 6.0 Package locking and package definition locking below.


1.1 The current package on startup

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.



2.0 Hierarchical Packages

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.


2.1 Hierarchical Package Terminology

Here is the terminology we will use when discussing hierarchical packages:


2.2 The problem with dots 1: find-package with names that begin with dots

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.


2.3 The problem with dots 2: names and nicknames that end with dots

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).


2.4 Defining hierarchical packages

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.


2.5 Package nicknames: absolute and relative

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 is right package to resolve 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):

2.5.1 Names and Nicknames created with :flat t

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): 

2.7 Resolving relative package names

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

2.7 Hierarchical package specified with nicknames

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): 

2.8 Hierarchical package anomalies

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.

BETA NOTE: The correct behavior for these cases is still under review. Behavior may change in the final release.


2.9 Package prefixes reserved by Allegro CL

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.


2.10 Functions for hierarchical packages

To facilitate using hierarchical packages, there are the functions package-parent and package-children.



3.0 Packages in Allegro CL

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.


4.0 Notes on specific packages

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.



5.0 Package nicknames and alternate names

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 (nil means none)

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.



6.0 Package locking and package definition locking

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.


6.1 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.


6.2 Package definition locking

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 or nil 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

  1. the value of *enable-package-locked-errors* is nil;
  2. the violation is dynamically inside the body of a call to the macro without-package-locks;
  3. 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.


6.3 Implementation packages

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))

6.4 Package locked errors

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.


6.5 Locally circumventing package locked errors

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.


6.6 The packages locked by default

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

6.7 Justification for package locking

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-2019, Franz Inc. Oakland, CA., USA. All rights reserved.
This page has had significant revisions compared to the 9.0 page.
Created 2019.8.20.

ToCDocOverviewCGDocRelNotesFAQIndexPermutedIndex
Allegro CL version 10.0
Significantly revised from 9.0.
9.0 version