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

Packages



Here are my notes on CMUC:<FAHLMAN.SLISP>PACKAGE.MSS.108.

Summary

  Item	Importance	Notes
  (1)	Medium		Propose changing "FOO#:BAR" to "#:FOO:BAR".
  (2)	Large		Propose flushing "#:" notation on symbols with NIL
			in their package cell.
  (3)	Small		Questioning use of PUSHNEW in USE-PACKAGE.
  (4)	Small		Wording issue in definition of "UNEXPORT".
  (5)	Tiny		Syntax in "DECLARE-PACKAGE".
  (6)	Medium		Setting *PACKAGE*, etc in init files.
  (7)	Small		LIST-ALL-PACKAGES and anonymous packages.
  (8)	Medium		Adding an optional PACKAGE argument to IMPORT, etc.
  (9)	Medium		Forcing symbols to print with[out] package prefixes.

-----

(1) I dislike "#:" in the middle of a name for several reasons.

    * I think it is ugly. It visually breaks up the symbol in a bad way. 

    * "#" is defined as a token terminator. This would have to be redefined.
      I note (p219, Colander Edition -- sorry; I have no Laser edition)
      there are no non-terminating macro sequences in the attributes table. I
      think this is wise from the point of view of novices. The presence of
      initially defined non-terminating macro sequences would just further
      complicate the knowledge of Lisp syntax a novice would need.

    * I would prefer a prefix notation such as "#:FOO:BAR" rather than 
      "FOO#:BAR". (If not "#:", some other prefix dispatch.) Thinking ahead
      to the multi-level packages for a moment, and given that package ids
      are strings (not symbols), would one write "FOO#:BAR:BAZ" or
      "FOO#:BAR#:BAZ" or ... I would prefer they lead off with an
      identification that the symbol coming up will be an internal one 
      and then give a normal qualified reference. eg, you could define 
      #: to just bind some (unexported) variable 
      *COMPLAIN-ABOUT-INTERNAL-PACKAGE-REFERNCES* to NIL and re-call READ
      without hairing up the language syntax.

    * If "#:" is used to mark symbols with no package cell, it is overloaded
      and visually misleading to have it mean both things.

(2) I dislike visually marking symbols that have no package cell.

    * When writing symbols out to a file and reading them back in, there's
      a high percentage of chance it really doesn't matter what package
      they are read into. To take a simple example, 
       (READ-FROM-STRING (FORMAT NIL "~S"
                    	     (LET ((V (GENSYM))) `(LAMBDA (,V) ,V))))
      won't even "work".

      You'd expect this with gensyms but its more irritating if you've 
      inherited some symbol from another package and you've uninterned
      the symbol from the source package. Suddenly, perfectly valid symbols
      may appear as if "gensymed" and will lose this property of being
      EQ.

      I guess the following properties are relevant ...

	(a) Symbols which were EQ before a PRINT-READ cycle should be EQ 
            afterward.
        (b) Symbols which were not EQ before a PRINT-READ cycle should not be
	    EQ afterward.
        (c) A symbol which was EQ to some other symbol not involved in
            a PRINT-READ cycle should still be EQ to it after such a cycle.

     Given that property (c) is in general very hard to assure, I still place
     a higher priority on (a) than on (b). Printing symbols out with no 
     annotation will guarantee (a) but may violate (b). Printing symbols out
     with the proposed "#:" marking (as I understand it) seems to violate 
     (a) while guaranteeing (b).


     Further, I think people will see "#:" coming out before gensysms for ages
     before they see the other case. I predict this will cause great debugging
     confusion for people that don't understand the other cases where this can
     happen and who have from many experiences come to associate "#:" with 
     gensyminess, not with the heuristic feature off of which it drives.

     An organized plan for treating gensyms would be nice, but in the absence
     of one (I don't think we have time for that now) I don't think that 
     marking things that appear to be gensyms.

     As a minor issue, "#:" would then be free for use in item (1) above.

(3) I'm not sure about using PUSHNEW rather than PUSH after a DELETE
    when calling things like USE-PACKAGE. It seems to me that users will
    expect the most recent call to USE-PACKAGE to have priority. Imagine
    a package A with an external symbol FOO on it. Imagine a package B 
    which does USE-PACKAGE A and then shadows FOO. Imagine some package C,
    the writer of which notices that A:FOO isn't provided in B and who doesn't
    realize that A is included in B. He might ask to USE-PACKAGE A and be
    confused that A:FOO still isn't visible. 

    I'm not so much saying this should be changed as I'm curious why things
    are supposed to happen as documented. Is there an alternative scenario
    that makes mine look less important?

(4) "If @b[unexport] is given a symbol that is already available
     as an internal symbol in the current package, it does nothing; ..."

    I guess my view was that "external" symbols are in some sense a subset
    of "internal" ones; ie, when working "internally" to a package, i expect
    "external" symbols are available (and they are). I was surprised, then,
    by this wording. Does it mean the same as, and would it be clearer as:

    "If @b[unexport] is given a symbol that is already available
     only as an internal symbol in the current package, it does nothing; ..."

(5) In DECLARE-PACKAGE's description , shouldn't you say @b[:nicknames], 
    etc. or @i[nicknames]. I should think @i[:nicknames] would be confusing.

(6) Re: LOAD binding *PACKAGE*
    The LispM has a problem with init files. People like to call pkg-goto
    and assign BASE,IBASE in their inits and find themselves thwarted by
    implicitly bound variables. A popular way to circumvent this problem 
    is by doing (PROCESS-RUN-FUNCTION #'(LAMBDA () (SETQ IBASE 10.)), etc.
    This seems pretty drastic. Will Common Lisp address this issue?

(7) Are packages always global, named objects?  Will there be a provision for 
    anonymous packages or packages rooted elsewhere besides GLOBAL?
    In such an event, should LIST-ALL-PACKAGES be constrained to return 
    even anonymous packages?

(8) IMPORT, EXPORT, etc. use the "current package".  I would prefer to have
    them take &OPTIONAL (PACKAGE *PACKAGE*) since I find it very ugly to write
    (LET ((PACKAGE *PACKAGE*)) (IMPORT ...)) if I happen not to have that 
    package selected.

(9) There are occasionally times when one would like a symbol to be printed
    with any package prefix unconditionally. Such is the case for APROPOS,
    for example. I would like the method by which I can make this happen be
    explicit. On the LispM, one resorts to binding PACKAGE to NIL or
    (pkg-find-package "GLOBAL"), but these "solutions" lose awfully if you
    get a breakpoint in those packages since you either end up finding you
    have a bad value for package (and recursively losing) or not finding 
    that you do (and losing in other ways). Perhaps a variable 
    *FORCE-PACKAGE-PREFIXES* which could be set T/NIL. Better still, perhaps
    a variable *PRINT-PACKAGE-PREFIXES* which could be set 
	:ALWAYS	Always print package prefixes
	:NEVER	Never print package prefixes
	:MAYBE	Print package prefixes when not "obvious"
	fn	A one-arg predicate which returns T if the package prefix 
		should be displayed and NIL otherwise.
    Setting it to :NEVER would be great when you want to do simple symbol
    manipulation unrelated to Lisp variables without getting bogged down in
    package I/O behavior. I have some applications where this would have been
    very handy.

--kmp