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

Issue: DEFPACKAGE (version 3)



re: ... why don't you just write up the proposal your way, leaving out
    arguments comparing it with the previous proposal, and then I will 
    either criticize it constructively or accede to it.

Well, ok, but all I really wanted to do was to get consensus on the one
point of removing :IMPORT and :SHADOWING-IMPORT.

Here is your version 2 from 23-Mar-88 with that deletion, and with the 
following emmendations, all of which are minor except for (3):
  (1) "symbol" --> "symbol-name" in numerous places, as per your mail
      message of "Date: Fri, 20 May 88 22:12 EDT"; also added appropriate
      commentary about depending only the "name", not the symbol.
  (2) Specify that :IMPORT-FROM (and :SHADOWING-IMPORT-FROM) signals an 
      error if any of the specified symbols do not already exist in the 
      "from" package.
  (3) Explicitly permit EXPORT to work after the other options, so that
      it can apply to imported and inherited symbols, as well as to
      absolutly fresh ones; this is new -- I hope you can agree to it, or
      give constructive criticism.
  (4) Added, and updated, references to Issues IN-PACKAGE-FUNCTIONALITY
      and PROCLAIM-ETC-IN-COMPILE-FILE; also added my "support" for the
      former into the Discussion section.
  (5) Added an alternate form under Examples; added "canonicalization"
      comment to Discussion.
  (6) Re-order the presentation of the options to accord with a revised
      order for the "7 Extremely Randoms" of CLtL p191 [not very important].


-- JonL --


!
Issue:         DEFPACKAGE

References:    CLtL section 11.7.
               Issue: IN-PACKAGE-FUNCTIONALITY

Category:      ADDITION

Edit history:  Version 1, 12-Mar-88, Moon
               Version 2, 23-Mar-88, Moon, changes based on discussion
               Version 3, 27-Mar-88, JonL 
		(remove :import, :shadowing-import; allow :export to work on
		 imported and inherited; update references to in-package, etc.)


Problem description:

The package functions included in CLtL encourage a programming style
that tends to evoke the worst aspects of the package system.  The
problem is that if the definition of a package is scattered through
a program, as a number of individual forms, it is very easy to read
a symbol before the package setup needed to read that symbol correctly
has been accomplished.  Three examples: an inherited symbol that should
have been shadowed might be accessed; a single-colon prefix might be
used for a symbol that will later be exported, causing an error; a local
symbol might be accessed where a symbol that will later be imported or
inherited was intended.  These problems can be difficult to understand
or even to recognize, are difficult to recover from without completely
restarting the Lisp, and give Common Lisp a bad name.

Proposal (DEFPACKAGE:ADDITION):
          
Add a DEFPACKAGE macro to the language.  It encourages putting the
entire definition of a package in a single place.  It also encourages
putting all the package definitions of a program in a single file, which
can be loaded before loading or compiling anything that depends on those
packages.  This file can be read in the USER package, avoiding any
package bootstrapping issues.

In addition, DEFPACKAGE allows a programming environment to process
the whole package setup as a unit, providing better error-checking and
more assistance with package problems, by dint of global knowledge of
the package setup.

Also expand MAKE-PACKAGE (and IN-PACKAGE, unless the cleanup Issue
IN-PACKAGE-FUNCTIONALITY is adopted) to take all the same keyword
arguments as DEFPACKAGE, for consistency.

The syntax of DEFPACKAGE is

  (DEFPACKAGE package-name {option}*)

where each option is a list of a keyword and arguments.  Nothing in a
DEFPACKAGE form is evaluated.

'package-name' is a symbol or a string; if a symbol, only its name
matters, not what package it is in.  If a string, capitalization
matters, normally uppercase is used.

Standard options for DEFPACKAGE are listed below.  Additional options
might be present in an implementation, and each implementation must
signal an error if an option not recognized by that implementation is
present.  Additional implementation-dependent options might take the
form of a keyword standing by itself as an abbreviation for a list
(keyword T); this syntax should be properly reported as an unrecognized
option in implementations that do not support it.

Each option may appear at most once.  If duplicate options are present,
DEFPACKAGE signals an error.

(:NICKNAMES {package-name}*)
        Set the package's nicknames to the specified names.

(:USE {package-name}*)
        Inherit from the specified packages.

(:SHADOW {symbol-name}*)
        Create the specified symbols in the package being defined, and 
        place them on the shadowing symbols list.   Each 'symbol-name' 
        argument must be either a string or a symbol.  If given as a
        symbol, only its name is used; and in this case the shadowing 
        symbol entered into the package being defined is definitely not 
        the one given as argument, but rather a symbol of the same name 
        freshly created as a shadow in the package.

(:SHADOWING-IMPORT-FROM {(package-name {symbol-name}*)}*)
(:SHADOWING-IMPORT-FROM package-name {symbol}*)
        Find the specified symbols in the specified packages and import
        them into the package being defined, and place them on the 
        shadowing symbols list.  Each 'symbol-name' argument must be 
        either a string or a symbol.  If given as a symbol, only its 
        name is used; and in this case, the symbol that is imported is 
        not necessarily the one given as an argument, but rather the symbol 
        of that name accessible in the "from" package.   In no case will 
        symbols be created in any package other than the one being defined; 
        a continuable error is signalled if no symbol is accessible for 
        one of the names in its corresponding "from" package.  The second 
        syntax is simply a convenient abbreviation when only one package 
        is specified. 

(:IMPORT-FROM {(package-name {symbol-name}*)}*)
(:IMPORT-FROM package-name {symbol-name}*)
        Find the specified symbols in the specified packages and import
        them into the package being defined.  Each 'symbol-name' argument 
        must be either a string or a symbol.  If given as a symbol, only
        its name is used; and in this case, the symbol that is imported is 
        not necessarily the one given as argument, but rather the symbol 
        of that name accessible in the "from" package.   In no case will 
        symbols be created in a package other than the one being defined; 
        a continuable error is signalled if no symbol is accessible for 
        one of the names in its corresponding "from" package.  The second 
        syntax is simply a convenient abbreviation when only one package 
        is specified. 

(:EXPORT {symbol-name}*)
        Find or create symbols with the specified names and export them.
        Each 'symbol-name' argument must be either a string or a symbol.
        If given as a symbol, only its name is used; and in this case,
        the symbol that is made external in the defined package is not 
        necessarily the one given as an argument, but rather a symbol of
        that name freshly interned in the package being defined.  Note an 
        interaction with the :USE option, since intern'ing may inherit 
        symbols rather than creating new ones; note also an interaction 
        with the :IMPORT-FROM and :SHADOWING-IMPORT-FROM options, since 
        intern'ing will merely access an already imported symbol. 

(:SIZE integer)
        Declare the approximate number of symbols expected in the package.
        This is an efficiency hint only, so that the package's table will
        not have to be frequently re-expanded when new symbols are added
        to it (e.g., by reading in a large file "in" that package.)


The collection of symbol-name arguments given to the options :SHADOW,
:IMPORT-FROM, and :SHADOWING-IMPORT-FROM must all be disjoint; an error
is signalled otherwise.  In a chronological sense, the :EXPORT may be
thought of as ocurring last so that it can make reference to inherited
or imported symbols already created by the other three options.


Examples:

;;; Play it super-safe, and use only strings as names; do not even assume
;;;  assume that the package it is read in to "uses" LISP; do *not* create
;;;  any symbols whatsoever in the package that it is read in to.

(LISP:DEFPACKAGE "MY-PACKAGE"
  (:NICKNAMES "MYPKG" "MY-PKG")
  (:USE "LISP")
  (:SHADOW "CAR" "CDR")
  (:SHADOWING-IMPORT-FROM "VENDOR-COMMON-LISP"  "CONS")
  (:IMPORT-FROM 	  "VENDOR-COMMON-LISP"  "GC")
  (:EXPORT "EQ" "CONS" "FROBOLA")
  )

;;; A similar call, using symbols rather than strings as names; expects
;;;  to be read in to a package that "uses" LISP, and *may* create
;;;  random internal symbols in that package (such as MY-PACKAGE etc).

(DEFPACKAGE MY-PACKAGE
  (:NICKNAMES MYPKG :MY-PKG)
  (:USE LISP)
  (:SHADOW CAR :CDR #:CONS)
  )



Rationale:

See first paragraph of Proposal section.

Current practice:

Symbolics Common Lisp has always had a DEFPACKAGE, and uses it in 
preference to individual calls to EXPORT, IMPORT, SHADOW, etc.  The SCL 
version of DEFPACKAGE has quite a few additional options, but none of them
appear to be necessary to propose for Common Lisp at this time.

Cost to Implementors:

Should be small as the macro can be implemented simply as a bunch of
calls to existing functions.

Cost to Users:

No cost, this is upward compatible.

Cost of non-adoption:

Packages continue to be difficult to use correctly.

Benefits:

Guide users away from using packages in ways that get them into trouble.

Esthetics:

Neutral.

Discussion:

The "Put in seven extremely random user interface commands" mnemonic
described in CLtL p.191 could be removed, and the special compiler 
handling of these functions necessary to support that could be removed 
(except possibly for REQUIRE and PROCLAIM -- see the Issue 
PROCLAIM-ETC-IN-COMPILE-FILE).  As this would be an incompatible change,
it is not part of this proposal.

The issue IN-PACKAGE-FUNCTIONALITY recommends that IN-PACKAGE  be 
incompatibly changed to recognize only existing packages, not to create 
them.  IN-PACKAGE would then not accept any keyword arguments.
Moon (and JonL and KMP) thinks this is a reasonable idea, and is the 
subject of a separate proposal.  

The macroexpansion of DEFPACKAGE should be permitted to canonicalize
into the strings-as-name form, so that even though the source file
showed random symbols in the DEFPACKAGE form, the compiled file might
have only strings in it.