[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
SYMBOL-MACROLET-SEMANTICS
- To: cl-cleanup@sail.stanford.edu
- Subject: SYMBOL-MACROLET-SEMANTICS
- From: piazza%lisp.DEC@decwrl.dec.com (Jeffrey Piazza)
- Date: Fri, 29 Jul 88 14:09:49 PDT
Status: For Internal Discussion
Issue: SYMBOL-MACROLET-SEMANTICS
References: X3J13 document 88-002R, Chapter 2, pp. 2-81f.
Category: CHANGE
Edit history: 29-July-88, Version 1 by Piazza
Problem Description:
The SYMBOL-MACROLET construct introduced with CLOS in X3J13 document
88-002R, because it is specified as a macro, cannot make use of the
&environment argument mechanism to communicate with complex macros
appearing within its body. As a consequence, the behavior of
SYMBOL-MACROLET, when used in conjunction with side-effects and complex
macros, is inconsistent with that of MACROLET, and confusing to users.
Test Case:
(let ((a (make-array 5))
(i 0))
(macrolet ((place () `(aref a (incf i))))
(push x (place)))
i) ==> 1
(let ((a (make-array 5))
(i 0))
(symbol-macrolet ((place (aref a (incf i))))
(push x place))
i) ==> 2
Proposal (SYMBOL-MACROLET-SEMANTICS:FLUSH):
Remove SYMBOL-MACROLET from 88-002R. Remove WITH-ACCESSORS and
WITH-SLOTS, or modify them to use ordinary macros.
Rationale:
For most uses of SYMBOL-MACROLET, ordinary MACROLET can provide equivalent
expressive/abstraction power. E.g.,
(symbol-macrolet ((slot1 (slot-value foo 'slot1)))
(incf slot1))
becomes
(macrolet ((slot1 () (slot-value foo 'slot1)))
(incf (slot1)))
Proposal (SYMBOL-MACROLET-SEMANTICS:SPECIAL-FORM):
Change the definition of SYMBOL-MACROLET to specify that it is a special
form, which affects the evaluation environment for symbols. Enhance
MACROEXPAND and MACROEXPAND-1 so that they can expand a symbol macro.
Modify SETF et al to use the new MACROEXPAND and MACROEXPAND-1 to examine
even symbol subforms. Specify that the expansion of a symbol macro IS
subject to further macro expansion, and that ``recursive'' symbol macros
are an error. Specify that it is an error to try to SETQ a symbol macro.
Rationale:
The current specification of SYMBOL-MACROLET as a macro leads to
undesirable results if forms which produce side-effects are part of the
expansion of a symbol macro.
This potential for interaction between macros is exactly why &environment
arguments were originally added to macros. Changing SYMBOL-MACROLET to be
a special form, which communicates through the &environment arguments to
macros with MACROEXPAND and MACROEXPAND-1, would allow PUSH and SETF
(among others) to work with SYMBOL-MACROLET in the same way they work with
MACROLET.
This change cannot (reasonably) support the currently specified semantics
that the expansion text is "outside" the scope of the symbol macro. For
indeed, when the symbol macro is expanded, (a copy of) the expansion is
then within the scope of the SYMBOL-MACROLET, and should then be subject
to further scrutiny. The issue of "infinite expansion" of symbol macros is
no more dangerous than that of normal macros.
Finally, the rule that SETQ of a symbol macro must be treated as a SETF of
the expansion seems to be a kludge which was introduced only to support a
code-walking version of SYMBOL-MACROLET. If SYMBOL-MACROLET were changed
to be a special form, this rule would no longer be needed, and should be
eliminated in order to make the distinction between symbol macros and
variables cleaner.
Current Practice:
Portable Common Loops provides a code-walking implementation of
SYMBOL-MACROLET as specified in 88-002R. Symbolics Cloe has both a
code-walking version of a SYMBOL-MACROLET macro and compiler support for
a SYMBOL-MACROLET special form.
Cost to Implementors:
If SYMBOL-MACROLET is removed from the language, no one will bear any cost
of implementation.
If it is modified to be a special form, compilers and interpreters will
have to change, as well as MACROEXPAND, MACROEXPAND-1, and SETF (at
least).
Cost to Users:
If SYMBOL-MACROLET is converted to a special form, code-walking programs
will have to be modified to handle SYMBOL-MACROLET correctly. Those same
programs would have to be modified to handle the other special forms
specified in CLOS, anyway.
If SYMBOL-MACROLET is removed from the language, users will have to make
do with MACROLET. Users will be unable to overload names which already
have definitions as functions. E.g.,
(defclass foo () (car cdr))
(defun describe-foo (foo)
(macrolet ((car () (slot-value foo 'car))
(cdr () (slot-value foo 'cdr)))
...
Can't use normal car and cdr in here
...))
Cost of Non-Adoption:
SYMBOL-MACROLET will retain its confusing semantics, leading to bugs when
it interacts with complex macros and forms which produce side-effects.
Implementations which support ONCE-ONLY will break. For that matter, any
mechanism which examines code and assumes that "variables" have no side
effects will break.
Benefits:
SYMBOL-MACROLET-SEMANTICS:FLUSH reduces the implementation and maintenance
costs for a Common Lisp implementation. It also simplifies the language
by eliminating the concept of a "symbol macro."
SYMBOL-MACROLET-SEMANTICS:SPECIAL-FORM avoids the hairiest problems
surrounding interaction of macros (like SETF) and side effects, and makes
SYMBOL-MACROLET consistent with MACROLET.
Aesthetics:
There seem to be mixed feelings as to the desirability of SYMBOL-MACROLET
as a construct in the language. Some feel it hairs up the language while
offering only trivial benefit beyond what is already provided through
normal macros. Others herald it as a important new language feature.
If symbol macros are retained but SYMBOL-MACROLET made to be a special
form, aesthetics are improved by making symbol macros consistent with
normal macros.
Discussion:
As it was adopted by X3J13 as part of CLOS, there has been no formal
discussion on the pros and cons of SYMBOL-MACROLET on its own.
In favor of SYMBOL-MACROLET are the following arguments:
* It allows access to a different namespace for defining macros. That is,
it allows macros to be defined in the namespace previously used only by
variables. This can avoid name conflicts in certain situations.
* Certain "embedded languages" may be more easily implemented if
SYMBOL-MACROLET is available.
Arguments against SYMBOL-MACROLET include:
* It makes variable references opaque. That is, a symbol appearing as a
form is no longer necessarily a variable. Programs become correspondingly
more difficult to read and understand.
* There are other solutions to the problems of name collisions which
don't add this complexity to the language. Specifying prefixes for
WITH-SLOTS and WITH-ACCESSORS in the manner of DEFSTRUCT, for example,
would eliminate accidental name conflicts in practice.
* Symbol macros cannot accept arguments, and therefore cannot be used to
solve the name conflict problems in situations where macro arguments are
required.