* Paul Bowyer [2011-04-01 16:23] writes:
In my learning exercises, I have been using something like:
(eval-when (:compile-toplevel :load-toplevel :execute) (if (find-package "CH16") (delete-package "CH16")) ) (defpackage "CH16" (:use "COMMON-LISP" "UTIL") (:shadow "LENGTH" "MEMBER" "COUNT") (:export "LENGTH" "MEMBER" "BEFORE" "NUMBER-LISTP" "SAME-LENGTH1" "SAME-LENGTH2" "COUNT") )
(in-package "CH16")
I think the problem is that the code tries to delete the current package, i.e. the package stored in the variable *package*. You can also produce the error in a normal SBCL session without Slime:
cl-user> (load (compile-file "x.lisp")) [...] t cl-user> (in-package ch16) #<package "CH16"> ch16> (load (compile-file "x.lisp")) [...] debugger invoked on a SIMPLE-TYPE-ERROR in thread #<THREAD "initial thread" RUNNING {AA43859}>: *PACKAGE* can't be a deleted package: *PACKAGE* has been reset to #<PACKAGE "COMMON-LISP-USER">. [...]
COMPILE-FILE does something like (let ((*package* *package*)) <code-that-does-the-rest>) so that *package* is automatically reset to the original value at the end. But if *package* is the CH16 package before you call COMPILE-FILE and that CH16 package is deleted at compile-time, we end up with a deleted package in *package*.
Now, you may ask why *package* is CH16 when using Slime. That's because there is a (in-package ch16) form in the file and Slime tries to be friendly and automatically switches to that package.
Yes, this is really confusing.
CLTL2[*] has some good rules to avoid many of those situations:
In order to guarantee that compiled files can be loaded correctly, the user must ensure that the packages referenced in the file are defined consistently at compile and load time. Conforming Common Lisp programs must satisfy the following requirements.
- The value of *package* when a top-level form in the file is processed by compile-file must be the same as the value of *package* when the code corresponding to that top-level form in the compiled file is executed by the loader. In particular, any top-level form in a file that alters the value of *package* must change it to a package of the same name at both compile and load time; moreover, if the first non-atomic top-level form in the file is not a call to in-package, then the value of *package* at the time load is called must be a package with the same name as the package that was the value of *package* at the time compile-file was called.
- For every symbol appearing lexically within a top-level form that was accessible in the package that was the value of *package* during processing of that top-level form at compile time, but whose home package was another package, at load time there must be a symbol with the same name that is accessible in both the load-time *package* and in the package with the same name as the compile-time home package.
- For every symbol in the compiled file that was an external symbol in its home package at compile time, there must be a symbol with the same name that is an external symbol in the package with the same name at load time.
Some of the package related functions like delete-package, unintern, rename-package etc. can lead to those confusing situations. If possible, create the package structure once and don't modify it later. Obviously that's not always possible but now you know that you need to be careful when messing around with packages.
Helmut
[*] http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/html/cltl/clm/node224....