[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Issue: KILL-PACKAGE (Version 3)



Well, no one else had much to say and I had more time to think about
this, so I decided to try to merge your suggestions and mine. I think
I've satisfied both our stated goals -- let me know if I have not.
I changed a bunch of the details of the Proposal section to make it
signal more errors, and to specify the corrective action that happens
if you continue.

The changed sections are: Proposal, Test Case, and Current Practice.

Procyon and Lucid Lisp guys especially should check the Current Practice.

-----
Issue:        KILL-PACKAGE
References:   Packages (pp171-192), PACKAGE-NAME (p184), PACKAGEP (p76)
Category:     ADDITION
Edit history: 30-Sep-88, Version 1 by Pitman
	      01-Oct-88, Version 2 by Pitman
	      04-Oct-88, Version 3 by Pitman
		(provide for correctable errors in some cases)
Status:       For Internal Discussion

Problem Description:

  There is no way to get rid of 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 DELETE-PACKAGE, described as follows:

  DELETE-PACKAGE package                                 [Function]

   Deletes PACKAGE from all package system data structures. PACKAGE may
   be either a package or the name of a package.

   If PACKAGE is a package name (i.e., not type PACKAGE) which does not
   currently name a package, a correctable error is signalled. If
   continued, no deletion action is attempted. Instead, DELETE-PACKAGE
   immediately returns NIL.

   If PACKAGE is a package object (i.e., an object of type PACKAGE)
   which has already been deleted, no error is signalled and no further
   deletion action is attempted. Instead, DELETE-PACKAGE immediately
   returns NIL.

   If the designated package is used by other packages, a correctable
   error is signalled. If continued, the effect of UNUSE-PACKAGE is
   done to remove any dependencies, causing its external symbols to stop
   being accessible to those packages. Once this is done, DELETE-PACKAGE
   goes on to delete the package as it would have if no conflict had
   occurred.

   The principal effect of deleting the package is that the name and
   nicknames of the designated package cease to be recognized package
   names.

   Any symbols in the designated package still exist after this function
   is called. If their home package was not the package to be deleted, 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 once it has been
   deleted is undefined.

   DELETE-PACKAGE returns T (if the deletion attempt was successful).

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*) => ()

  (DELETE-PACKAGE *BAR-PACKAGE*)
  Error: Package BAZ uses package BAR.
  If continued, BAZ will be made to unuse-package BAR,
	        and then BAR will be deleted.
  Type :CONTINUE to continue.
  Debug> :CONTINUE
  				       => T

  (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
  except that an error is not signalled if the package is used.
  When a package is killed by PKG-KILL, the home package of all symbols
  in that package are left undisturbed (i.e., local symbols pointing to
  the killed package); this aspect is compatible with the stated proposal.

  Procyon Common Lisp has a DELETE-PACKAGE already. It returns the name
  of the package so deleted (as a string). [Perhaps it also differs in the
  correctability of the errors it signals? -kmp]
 
  Lucid Common Lisp provides DELETE-PACKAGE but the argument must be a
  package object.

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 DELETE-PACKAGE
  to take care of worrying about the effects of having deleted the package:
  normal programs need not bother testing a package for validity (using
  PACKAGE-NAME) before using it.

Cost of Non-Adoption:

  Getting rid of 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.