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

fixing our problems with setf



    Date: Tue, 13 Oct 87 16:45 EDT
    From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>

I have just a couple of comments.  I put them in as comments rather than
editing your text so it would be easier to see them.  Otherwise this
looks good, it seems the best compromise between what I have been
wanting to do with setf for sometime and backward compatibility.

    Here is the proposal I will send to the cleanup committee Wednesday
    evening, after incorporating any comments you have to offer:

    Issue:         SETF-CLOS

    References:    setf rules for what -place- can be (pp.94-7)
		   compile function (p.438)
		   defun macro (p.57)
		   disassemble function (p.439)
		   documentation function (p.440)
		   fboundp function (p.90)
		   flet special form (p.113)
		   fmakunbound function (p.92)
		   ftype declaration (p.158)
		   function special form (p.87)
		   function declaration (p.159)
		   inline declaration (p.159)
		   notinline declaration (p.159)
		   labels special form (p.113)
		   symbol-function and setf of symbol-function (p.90)
		   trace macro (p.440)
		   untrace macro (p.440)

    Category:      ADDITION

    Edit history:  Version 1, 13-Oct-87 Moon

    Problem description:

    The Common Lisp Object System needs a well-defined way to relate the
    name and arguments of a setting function to those of a reading function,
    because both functions can be generic and can have user-defined methods.
    We tried to hide the name and arguments of the setting function with
    macrology, but the complexity got out of hand.  It seems better to make
    this information explicit; the version of the CLOS specification that
    assumes the adoption of proposal SETF-CLOS:SETF-FUNCTIONS is much
    simpler in the relevant areas.

    Proposal (SETF-CLOS:SETF-FUNCTIONS): 

    Add to Common Lisp the concept of "setf functions".  Right now, Common
    Lisp only has "setf macros", which are defined by define-setf-method and
    both forms of defsetf.  Terminology:
      - a "setf macro" is something that produces code (or other
	specifications, as in define-setf-method) which, when evaluated,
	will perform the effect of an invocation of setf.
      - a "setf function" is something that is called to perform
	directly the effect of an invocation of setf.

You should say right here that a setf function is called by the default
expansion of setf (unless a setf macro was explicitly defined).

    The name of the setf function that is called to perform the effect of
    (setf (-name- ...) ...) is a list (setf -name-), where -name- is a
    symbol.  The functions, macros, and special forms defined in CLtL and
    listed in the References section above need to be enhanced to accept
    such lists in addition to symbols as function names.

    A setf function receives the new value to be stored as its first
    argument.  Thus, #'(setf foo) should have one more required parameter
    than #'foo, the first required parameter is the new value to be stored,
    and the remaining parameters should be the same as #'foo's parameters.

    A setf function must return its first argument, since setf is defined
    to return the new value.

    A definition of a setf function can be lexically local, like a
    definition of a reading function.  The following rules specify the
    behavior of SETF; note that these rules are ordered and the first rule
    to apply supersedes any later rules.  These rules are a consistent
    extension of the current behavior of Common Lisp and the Cleanup
    committee's resolution of issue GET-SETF-METHOD-ENVIRONMENT.  Only
    rule 4 is new with this proposal.

    Rules for the macroexpansion of (setf (foo x) y):

    (1) If the function-name foo refers to the global function definition,
    rather than a locally defined function or macro, and if there is a
    setf macro defined for foo, use the setf macro to compute the expansion.

    (2) If the function-name foo is defined as a macro in the current scope,
    use macroexpand-1 to expand (foo x) and try again.

    (3) If the function-name foo is defined as a special form in the current
    scope, signal an error.

    (4) Expand into the equivalent of
	(let ((#:temp-1 x)
	      (#:temp-2 y))
	  (funcall #'(setf foo) #:temp-2 #:temp-1))

    Note that rule 4 is independent of the scope of the function name
    (setf foo).  It does not matter if that scope is different from the
    scope of the function name foo.  This allows some nonsensical programs
    to be written, but does not seem harmful enough to justify making more
    complicated rules to compare the scopes of the two function definitions.

    Normally one does not define both a setf function and a setf macro
    for the same reading function.

    Normally one defines a local reading function and a local setf function
    together in a single FLET or LABELS.

(I give an example later).

    In the absence of any setf macro definition, SETF of a function expands
    into a call to the setf function.  This means that the setf function
    only needs to be defined at run time, not compile time.

Should be "Since in the absence of ..."? 

    Test Case:  (really more of an example than a test case)

    ;If setf of subseq was not already built into Common Lisp,
    ;it could have been defined like this
    (defun (setf subseq) (new-value sequence start &optional end)
      (unless end (setq end (length sequence)))
      (setq end (min end (+ start (length new-value))))
      (do ((i start (1+ i))
	   (j 0 (1+ j)))
	  ((= i end) new-value)
	(setf (elt sequence i) (elt new-value j))))

Another example would be:

(defun frobulate (mumble)
  (let ((table (mumble-table mumble)))
    (flet ((foo (x)
             (gethash x table))
           ((setf foo) (new x)
             (setf (gethash x table) new)))
      ..
      (foo a)
      ..
      (setf (foo a) b))))


    Rationale:

    By making the names and arguments of setting functions explicit, CLOS is
    considerably simplified.

This reduces the desire having a way to lexially bind setf macros
because code which doesn't use defsetf or define-modify-macro won't need
lexical setf macros it can just use lexical functions.


It would be good to point out that right now, many people are doing
something *like* this:

 (defsetf foo |setf FOO|)
 (defun foo (x) ..)
 (defun |setf FOO| (x new) ..)

and that these many similar styles will all be able to be expressed
with:

 (defun foo (x) ..)
 (defun (setf foo) (new x) ..)

The bringing together of these styles will make code more 'common'.  I
tried to capture this in the following paragraph but it doesn't quite
get it.

Many of the current styles of using setf are quite similar.  That code
will be be simplified because many people who have been using techniques
essentially equivalent to using setf functions with no setf macros in
the new technique will begin using a common mechanism.

    Current practice:

    A few Common Lisp implementations already have a similar feature,
    in that they have setting functions named (SETF reader).  I don't
    know of any implementation that has precisely the proposed feature.

    Adoption Cost:

    The main cost is generalization of a few functions to accept lists
    beginning with SETF where they now accept only symbols.  Implementations
    must add a data structure to store the function definition of a setf
    function, however, this can trivially be done with property lists or
    generated symbols.

    The cost of making the SETF macro expand into a call to a setf function,
    when it does not find a setf macro or a regular macro to expand, is
    negligible.

    This will be an incompatible change for Symbolics, since it already has
    setf functions but they do not take the same arguments as proposed here.
    However, the change is considered worthwhile.

    Cost of non-adoption:

    Non-adoption of this proposal would be a significant roadblock to the
    Common Lisp Object System.  Some major rethinking of CLOS would be
    required.

    Benefits:

    Allow CLOS to be defined without out-of-hand complexity.

    Conversion Cost:

    None, this is an upward-compatible change.

    Esthetics:

    SETF would be more esthetic, but less powerful, if it had only the
    proposed setf functions and did not have setf macros.  Such a major
    incompatible change is of course out of the question, however by
    stressing setf functions SETF could become easier to teach.

perhaps "by stressing the use of setf functions and no explicit setf
macros SETF could become easier to teach.".

I really believe that many people will stop defining setf macros once
this proposal is accepted.  

    Discussion:

    Note that in Common Lisp, setf macroexpansion is an operation on
    function names, not on functions.  It differs from some dialects of
    Scheme, such as T, in this respect.  This proposal does not attempt to
    change that.

    The following related features were considered but are specifically
    not being proposed at this time, since they are unnecessary for CLOS
    and appear not to improve the simplicity and esthetics of the language:

      Lexically local setf macros, that is, a cross between defsetf and
      macrolet.  This does not appear to be logically necessary.  Do all three
      ways of defining lexically global setf macros need local counterparts?
  
      Should we define the meaning of defmacro or macrolet of (setf foo)?
      This would be a fourth way to define a setf macro.
  
      Should we enhance the definition of global setf macros, for example to
      say that (macro-function '(setf foo)) returns an expander function that
      takes two arguments and returns five values?
  
      Should we introduce a new name for symbol-function, since it accepts
      non-symbols now?
-------