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

Package problem, revisted

   This is one reason that you should always use strings instead of symbols
   a DEFPACKAGE form.  To illustrate the horrors of using symbols, consider the

   (defpackage foo                    ;bad style!
     (:use common-lisp)
     (:import-from clos class-precedence-list)
     (:export bar baz))

   This form will create oodles of extraneous symbols in the current package
   read.  In fact, if this form is read into the FOO package, perhaps because
   the file attribute line, then trouble is sure to follow.  The reader will
   a symbol having the name "CLASS-PRECEDENCE-LIST" into the current package
   this form is read.  Then when the :IMPORT-FROM clause is executed, *boom*, a
   name conflict occurs.

   Contrast the previous form with the following paragon of beauty:

   (cl:defpackage "FOO"               ;much better!
     (:use "COMMON-LISP")
     (:import-from "CLOS" "CLASS-PRECEDENCE-LIST")
     (:export "BAR" "BAZ"))

   This form will never create any symbols in the current package.  See pages
   272-273 of CLtL/2 for a more detailed example.

I used to use symbols to refer to packages until I ran into the aforementioned
difficulties. Then I switched to using strings. But this too has its problems.
CommonLisp systems differ as to whether they use upper or lower case for
package names (much in the same way as the case of symbol print names can
differ). So I ran into problems trying to make a program portable across
numerous CommonLisp implementations. That was about three years ago and I
don't remember the exact details nor which was the offending implementation.
(I think it was Allegro on NeXT or some derivative of KCL/AKCL/IBCL).
What I seem to remember was that while most implementations would put the
symbol foo:bar in the package "FOO" one would put it in the package "foo" so
that if you created a package "FOO" and then interned a symbol foo:bar it
would go into a different package. I seem to remember that that implementation
correctly treated the symbols bar and BAR to be equivalent but was case
sensitive to package prefixes so that foo:BAR and FOO:BAR would be different

Now I don't know whether that was legitimate behavior within the spec. That
experience predated CLtL2 and though I haven't read CLtL1 in a while, I think
that CLtL1 didn't deal with this issue. I remember that the last time I read
CLtL2, it wasn't explicit on this issue either.

So the way around this that I have been using is to always use symbols in the
keyword package as package names and as anonymous symbol names whose package
would be determined from other context as in the :IMPORT-FROM and :EXPORT
clauses of DEFPACKAGE. Thus:

(defpackage :foo                    ;I don't know---is this better style?
  (:use :common-lisp)
  (:import-from :clos :class-precedence-list)
  (:export :bar :baz))

This only works if the canonical case for symbol print names is the same as
for package print names but at the time this seemed to work on all
implementations that I tried. I don't know if this is a reasonable strategy.
Could someone please tell me if this is appropriate style or not? Or is this
obsolete now.