[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Issue: KILL-PACKAGE (Version 1)
- To: CL-Cleanup@SAIL.Stanford.EDU
- Subject: Issue: KILL-PACKAGE (Version 1)
- From: Kent M Pitman <KMP@STONY-BROOK.SCRC.Symbolics.COM>
- Date: Fri, 30 Sep 88 17:17 EDT
Issue: KILL-PACKAGE
References: Packages (pp171-192), PACKAGE-NAME (p184), PACKAGEP (p76)
Category: ADDITION
Edit history: 30-Sep-88, Version 1 by Pitman
Status: For Internal Discussion
Problem Description:
There is no way to kill a package in Common Lisp.
This absence makes interactive development work tricky in some
implementations. If a package is accidentally built incorrectly, the
user must either rename the package to another package or start over
by reloading his program in a fresh lisp image.
Some programs need to create and destroy packages at runtime.
Without such a facility, some clumsy combination of RENAME-PACKAGE,
UNINTERN, and UNUSE-PACKAGE is usually made to work. However, it is
easy for a casual programmer to forget to undo some of the
bookkeeping, leading to unwanted effects.
Proposal (KILL-PACKAGE:NEW-FUNCTION):
Introduce the function KILL-PACKAGE, described as follows:
KILL-PACKAGE package [Function]
Kills PACKAGE by removing it from all package system data structures.
PACKAGE may be a package or the name of a package.
If PACKAGE names a package which does not exist, or is a package
object which has been killed already, an error is signalled.
The name and nicknames of the designated package cease to be
recognized package names.
If the designated package is used by other packages, the effect of
UNUSE-PACKAGE is done to remove that dependency, causing its external
symbols to stop being accessible to those packages.
Any symbols in the designated package still exist after this function
is called. If their home package was not the package to be killed, the
home package will be unchanged. If their home package was that package,
the home package after this operation is unspecified; the effect of
printing such symbols is also unspecified.
The designated package persists after this function is called.
PACKAGEP is still true of it, but PACKAGE-NAME will return NIL.
The effect of any other package operation on PACKAGE is undefined.
KILL-PACKAGE returns T.
Test Case:
(SETQ *FOO-PACKAGE* (MAKE-PACKAGE "FOO" :USE NIL))
(SETQ *FOO-SYMBOL* (INTERN "FOO" *FOO-PACKAGE*))
(EXPORT *FOO-SYMBOL* *FOO-PACKAGE*)
(SETQ *BAR-PACKAGE* (MAKE-PACKAGE "BAR" :USE '("FOO")))
(SETQ *BAR-SYMBOL* (INTERN "BAR" *BAR-PACKAGE*))
(EXPORT *FOO-SYMBOL* *BAR-PACKAGE*)
(EXPORT *BAR-SYMBOL* *BAR-PACKAGE*)
(SETQ *BAZ-PACKAGE* (MAKE-PACKAGE "BAZ" :USE '("BAR")))
(SYMBOL-PACKAGE *FOO-SYMBOL*) => #<Package "FOO">
(SYMBOL-PACKAGE *BAR-SYMBOL*) => #<Package "BAR">
(PRIN1-TO-STRING *FOO-SYMBOL*) => "FOO:FOO"
(PRIN1-TO-STRING *BAR-SYMBOL*) => "BAR:BAR"
(FIND-SYMBOL "FOO" *BAR-PACKAGE*) => FOO:FOO, :EXTERNAL
(FIND-SYMBOL "FOO" *BAZ-PACKAGE*) => FOO:FOO, :INHERITED
(FIND-SYMBOL "BAR" *BAZ-PACKAGE*) => BAR:BAR, :INHERITED
(PACKAGEP *FOO-PACKAGE*) => T
(PACKAGEP *BAR-PACKAGE*) => T
(PACKAGEP *BAZ-PACKAGE*) => T
(PACKAGE-NAME *FOO-PACKAGE*) => "FOO"
(PACKAGE-NAME *BAR-PACKAGE*) => "BAR"
(PACKAGE-NAME *BAZ-PACKAGE*) => "BAZ"
(PACKAGE-USE-LIST *FOO-PACKAGE*) => ()
(PACKAGE-USE-LIST *BAR-PACKAGE*) => (#<Package FOO>)
(PACKAGE-USE-LIST *BAZ-PACKAGE*) => (#<Package BAR>)
(PACKAGE-USED-BY-LIST *FOO-PACKAGE*) => (#<Package BAR>)
(PACKAGE-USED-BY-LIST *BAR-PACKAGE*) => (#<Package BAZ>)
(PACKAGE-USED-BY-LIST *BAZ-PACKAGE*) => ()
(KILL-PACKAGE *BAR-PACKAGE*)
(SYMBOL-PACKAGE *FOO-SYMBOL*) => #<Package "FOO">
(SYMBOL-PACKAGE *BAR-SYMBOL*) is unspecified
(PRIN1-TO-STRING *FOO-SYMBOL*) => "FOO:FOO"
(PRIN1-TO-STRING *BAR-SYMBOL*) is unspecified
(FIND-SYMBOL "FOO" *BAR-PACKAGE*) is undefined
(FIND-SYMBOL "FOO" *BAZ-PACKAGE*) => NIL, NIL
(FIND-SYMBOL "BAR" *BAZ-PACKAGE*) => NIL, NIL
(PACKAGEP *FOO-PACKAGE*) => T
(PACKAGEP *BAR-PACKAGE*) => T
(PACKAGEP *BAZ-PACKAGE*) => T
(PACKAGE-NAME *FOO-PACKAGE*) => "FOO"
(PACKAGE-NAME *BAR-PACKAGE*) => NIL
(PACKAGE-NAME *BAZ-PACKAGE*) => "BAZ"
(PACKAGE-USE-LIST *FOO-PACKAGE*) => ()
(PACKAGE-USE-LIST *BAR-PACKAGE*) is undefined
(PACKAGE-USE-LIST *BAZ-PACKAGE*) => ()
(PACKAGE-USED-BY-LIST *FOO-PACKAGE*) => ()
(PACKAGE-USED-BY-LIST *BAR-PACKAGE*) is undefined
(PACKAGE-USED-BY-LIST *BAZ-PACKAGE*) => ()
Rationale:
This facility corrects the deficiency described in the problem description.
Current Practice:
Symbolics has a function PKG-KILL which satisfies the proposed behavior.
When a package is killed the home package of all symbols in that package
are left undisturbed (i.e., local symbols pointing to the killed package).
Cost to Implementors:
The cost of providing this facility is probably small.
Cost to Users:
Very slight to none. This change is essentially compatible.
Some code which cached packages in variables might have to be slightly
more cautious, but experience in the Symbolics implementation suggests
that it's really the responsibility of the person doing the KILL-PACKAGE
to take care of worrying about the effects of having killed the package:
normal programs need not bother testing a package for validity (using
PACKAGE-NAME) before using it.
Cost of Non-Adoption:
Killing a package would continue to be difficult to do portably.
Benefits:
Better control of storage usage would be available portably.
Aesthetics:
No significant effect.
Discussion:
This was discussed as part of a larger bulk issue of how to undo all
sorts of definitions. Since that proposal has not gone anywhere
(perhaps bogged down under its own weight), this subtopic has been
broken off for separate discussion.
Pitman supports this addition.