From: Jamie Zawinski
Subject: Re: Summary of Macro Question
Date: 
Message-ID: <21866@pasteur.Berkeley.EDU>
In article <·····@shemp.CS.UCLA.EDU> ···@maui.cs.ucla.edu (Scott Turner) writes:
> 	(defmacro rule::define (...)
> 	  `(progn
> 		(import 'rule::*spec*)
> 		... ))
> 
> This seems to work, and has the advantage of relieving the user of having 
> to deal with such things.  (Which of course is the whole point of the macro.)
> 
> Similarly, several people suggested making the user type out "rule::*spec*"
> but I don't consider that an acceptable interface.

Actually, I doubt this would work if loaded into a fresh environment.  Consider
what happens when you type the form

	(rule:define rule-name
		(test (list? *spec*))
		(body (car *spec*)))

First it is read, producing a list.  In this list are the symbols RULE::DEFINE
and *SPEC* (in the current package), among others.  Next, this list is 
evaluated.  Since the car of the list is a macro, the macroexpansion function
is called to produce another list to evaluate instead.  This would be 
something like

	(progn (import 'rule::*spec*)
	       ...
		 (lambda (*spec*) (list? *spec*))
		...)

Since the call to IMPORT is a part of the macroexpansion output, the 
symbol-names have already been resolved; that happens at read-time.  
Even before the above form is evaluated, there is a symbol called "*SPEC*" in
the current package.  When you call IMPORT to drag the symbol called "*SPEC*"
from the RULE package into the current package, you will get a name-conflict
error.

Rather than trying to change the package hierarchy at run-time, set it up
beforehand.  At the front of the file which defines the rule system itself, 
add these forms:

	(in-package "RULE")
	(export '(rule::define rule::*spec*) "RULE")

and in the package which defines rules, add a form like

	(in-package "RULE-USER" :use '("LISP" "RULE"))

This says that the rule package exports two symbols as its interface to the
outside world: DEFINE and *SPEC*.  Packages which :USE the rule package
will inherit those two symbols as internal; that is, the symbols 
RULE-USER::*SPEC* and RULE::*SPEC* will be the same.  They are not just 
equivalent, they different names for the same symbol.  this will let the 
code's users type 

	(define rule-name
		(test (list? *spec*))
		(body (car *spec*)))

and get the right versions of both *SPEC* and DEFINE.

It is very easy to make the package state inconsistent; since simply typing
a symbol causes it to be created and interned if it does not exist in the
current package, if, before creating the RULE-USER package, you happened to
say something like

	(in-package "RULE-USER")
	'*spec*		; <--- any mention of this symbol

then the form

	(in-package "RULE-USER" :use '("LISP" "RULE"))

will no longer work, because the RULE-USER package is now in an incompatible
state.  This is why it's usually a good idea to set up the package hierarchy 
the way you want it, and then not touch it again.  When you have code that 
alters the package state at run-time (like the define-rule macro quoted at 
the top of this message) you can get into some strange, hard to reproduce,
hard to debug situations.  

>> If you don't feel like you fully understand the package system, don't use
>> it.  Put all of your code in one package until you do.
> 
> Which is probably good advice, though I wonder how one is to learn about the
> package system without trying out things.

You are, of course, absolutely right.  I hope this message was a little less
snide.  :-)

		-- Jamie