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

Issue: DEFINING-MACROS-NON-TOP-LEVEL (Version 7)



I very strongly oppose this business of having all macro forms treated in
their own lexical environment. Among other things, this makes MACROLET and
DEFMACRO asymmetric. 

I am ammenable to special cases for DEFUN because its effect takes place
at runtime.

I think the correct solution to this situation is to say that if any of
these defining forms occur in other than the toplevel environment, then it
is as if EVAL was used.

Briefly, that means that I think that
 (DEFUN FOO (X) (DEFMACRO BAR (Y) ...) ...)
should be treated conceptually like:
 (DEFUN FOO (X) (EVAL '(DEFMACRO BAR (Y) ...)) ...)

I don't really mind some implementation does the optimization of
implementing this behavior by:
 (DEFUN #:FOO-INTERNAL-0 (Y) ...)
 (DEFUN FOO (X) (SETF (MACRO-FUNCTION 'BAR) #'#:FOO-INTERNAL-0) ...)
in order to make sure the stuff gets compiled, as long as the advertised
behavioral equivalency to EVAL is preserved.

I think very strongly that there is no other rational interpretation.

-----
None of the above is dependent on the following, but As an addendum, I think
the right solution to the EVAL-WHEN problem is to say that in any non-toplevel
position, EVAL-WHEN simply behaves as if defined by:
 (DEFMACRO EVAL-WHEN (TIMES &BODY FORMS)
   (IF (MEMBER 'EVAL TIMES) `(EVAL '(PROGN ,@FORMS))
       NIL))
Note well that a use of (EVAL-WHEN (EVAL LOAD) ...x...) would no longer be
equivalent to (PROGN ...x...) because the environment is different in non-top-level
positions; the former would use null lexical, while the latter would use current
lexical. Nevertheless, the change would be compatible because the only place you
could tell the difference would be in non-top-level positions, where EVAL-WHEN
is currently disallowed.

With such a definition of EVAL-WHEN, a [meta-circular] definition of DEFMACRO 
might look like:
 (DEFMACRO DEFMACRO (NAME BVL &BODY FORMS)
   `(PROGN (EVAL-WHEN (COMPILE)
	     (COMPILER::NOTICE-DEFMACRO ',NAME ',BVL ',FORMS))
	   (EVAL-WHEN (EVAL LOAD)
	     (SETF (MACRO-FUNCTION ',NAME)
	           #'(LAMBDA (#:CALL #:ENV)
		       (COMPILER::DEFMACRO-HACK-ARGUMENTS ((#:CALL #:ENV) ,BVL)
			  ,@FORMS))))))

This would imply:

 - At toplevel in the compiler, the compiler would notice the definition.
 - At toplevel in the compiler, the compiler would set things up to have the
   compiled definition restored.
 - In any non-top-level position, the behavioral equivalent of EVAL in a toplevel
   environment would be done, so the macro would take effect at runtime.

My proposal is not designed to let you do
 (LET ((X 3)) (DEFMACRO FOO () X))
but not by some flaw: I don't believe that this is appropriate.

Under my theory of EVAL-WHEN, the way you would define DEFUN to capture the
lexical environment (glossing the weird hairy implicit-block issue) is:

 (DEFMACRO DEFUN (NAME BVL &BODY FORMS)
   `(PROGN (EVAL-WHEN (COMPILE) (COMPILER::NOTICE-DEFUN ',NAME ',BVL ',FORMS))
	   (SETF #',NAME #'(LAMBDA ,BVL ,@FORMS))
	   ',NAME))


This would imply:

 - At toplevel in the compiler, the compiler would notice the definition.
 - At toplevel in the compiler, the compiler would set things up to have the
   compiled definition restored.
 - In any non-top-level position, the compiler would not notice the definition
   in a formal way, but it would compile it in the current lexical contour
   and the definition would take place when the code was executed.

This would, therefore, permit
 (LET ((X 3)) (DEFUN FOO () X))
and
 (DEFUN INITIALIZE-FOO (X) (DEFUN FOO () X))