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

SYMBOL-MACROLET-SEMANTICS



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.