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

Issue: FUNCTION-NAME (Version 1)

Here is the new proposal for the SETF issue that I put up on slides at
the X3J13 meeting.  It's been refined a bit, according to the
suggestions various people made.

Assuming this remains in the Cleanup subcommittee, perhaps Larry should
put this on the forthcoming letter ballot so we don't necessarily have
to wait until March to deal with it.

Issue:         FUNCTION-NAME

References:    SETF rules for what -place- can be (pp.94-7)
               FBOUNDP function (p.90)
               FMAKUNBOUND function (p.92)
               FUNCTION special form (p.87)
               SYMBOL-FUNCTION and setf of symbol-function (p.90)
               88-002R pages 1-21, 2-21, 2-26, 2-39, 2-44, 2-46, 2-51, and 2-55
               (There are additional references for the MEDIUM and LARGE
                proposals, but they are not listed here.  They're obvious.)

Related issues: SETF-FUNCTION-VS-MACRO, SETF-PLACES (both subsumed by this)

Category:      ADDITION

Edit history:  Version 1, 23-Jan-89, by Moon 
                              (based on discussion at X3J13 meeting)

Problem description:

The Common Lisp Object System needs a well-defined way to relate the name
and arguments of a writer function to those of a reader function, because
both functions can be generic and can have user-defined methods.  The way
that was adopted into Common Lisp when X3J13 voted to accept document
88-002R was to use a list (SETF reader) as the name of the writer function.

Some changes to the non-object-oriented portion of Common Lisp are required
in order to support this.

This issue has three proposals.

  Add a new concept "function-name" (called "function-specifier" in
  88-002R).  A function-name is either a symbol or a 2-element list whose
  first element is the symbol SETF and whose second element is a symbol.
  Implementations are free to extend the syntax of function-names to
  include lists beginning with additional symbols other than SETF.

  Add a new function (FDEFINITION function-name), which returns the
  current global function definition named by function-name, or signals
  an error if there is no global function definition.  This follows all
  the same rules listed for SYMBOL-FUNCTION in CLtL p.90.

  Add SETF of FDEFINITION to change the current global function definition
  named by a function-name.  This follows all the same rules listed for

  Change the FBOUNDP and FMAKUNBOUND functions, and the FUNCTION special
  form, to accept function-names in place of symbols.  Implementation
  defined extensions to the syntax of function-names cannot use the
  symbol LAMBDA, since FUNCTION already uses that symbol.

  Change the rules for SETF places (CLtL pp.94-7) by adding the following
  clause after all the existing clauses:

   - Any other list whose first element is a symbol, call it reader.
     In this case, SETF expands into a call to the function named by the
     list (SETF reader).  The first argument is the new value and the
     remaining arguments are the values of the remaining elements of
     -place-.  This expansion occurs regardless of whether reader or
     (SETF reader) is defined as a function locally, globally, or not at
     all.  For example,
         (SETF (reader arg1 arg2...) new-value)
     expands into a form with the same effect and value as
         (LET ((#:temp-1 arg1)          ;force correct order of evaluation
               (#:temp-2 arg2)
               (#:temp-0 new-value))
           (FUNCALL (FUNCTION (SETF reader)) #:temp-0 #:temp-1 #:temp-2...)).

  to implement the above change to the rules.
  Document that a function named (SETF reader) should return its first
  argument as its only value, in order to preserve the semantics of SETF.

  Change the macro DEFGENERIC and the function ENSURE-GENERIC-FUNCTION to
  refer to the function FDEFINITION where they now refer to the function

  Change the macros DEFCLASS, DEFGENERIC, and DEFMETHOD, the special forms
  ENSURE-GENERIC-FUNCTION to use the term "function-name" where they now
  use the term "function-specifier" or "function specifier".


  This is the minimum change to Common Lisp needed to do what 88-002R says
  about (SETF reader).  Giving implementations freedom to extend the syntax
  of function-names allows for current practice.  Changing the name from
  "function-specifier" to "function-name" avoids confusion and improves
  consistency with the rest of the language, at the cost of a few small
  changes to 88-002R.


  Everything in FUNCTION-NAME:SMALL, and in addition:

  Change the DEFUN macro to accept a function-name for its name argument,
  instead of only accepting a symbol.  If function-name is (SETF sym),
  the body is surrounded by an implicit block named sym.


  Keeping DEFUN consistent with DEFMETHOD is a good idea.  Also 88-002R
  says "The name of a generic function, like the name of an ordinary
  function, can be either a symbol or a two-element list whose...", which
  implies this change to DEFUN.


  Everything in FUNCTION-NAME:MEDIUM, and in addition the following
  numbered points, each of which could be adopted independently,
  except where explicitly noted:

  1. Change the function COMPILE to accept a function-name as its name

  2. Change the function DISASSEMBLE to accept a function-name as its name

  3. Change the FTYPE, INLINE, and NOTINLINE declarations and proclamations
  to accept function-names, not just symbols, as function names.

  4. Change the FLET and LABELS special forms to accept a function-name in
  the name position, not just a symbol.

  5. Change the TRACE and UNTRACE macros to accept function-names, not just
  symbols, in the function name positions.

  6. Change the ED function to accept (ED function-name) in place of
  (ED symbol).

  7. Change the syntax of a function call to allow a function-name as the
  first element of the list, rather than allowing only a symbol.

  8. Change the DEFMACRO macro and the MACROLET special form to accept a
  function-name in the name position, not just a symbol.  Change the
  MACRO-FUNCTION function to accept function-names, not just symbols.
  Change the last rule for SETF places to use
    ((SETF reader) #:temp-0 #:temp-1 #:temp-2...)
  in place of
    (FUNCALL (FUNCTION (SETF reader)) #:temp-0 #:temp-1 #:temp-2...)
  so that (SETF reader) can be defined as a macro.  This depends on item
  7.  If item 4 is rejected, MACROLET should be stricken from this item.

  9. Add an optional environment argument to FDEFINITION, SETF of
  FDEFINITION, FBOUNDP, and FMAKUNBOUND.  This is the same as the
  &environment argument to a macroexpander.  This argument can be used to
  access local function definitions, to access function definitions in the
  compile-time remote environment, and to modify function definitions in
  the compile-time remote environment.

  10. Change the second, third, fourth, fifth, seventh, and ninth rules for
  SETF places so that they only apply when the function-name refers to the
  global function definition, rather than a locally defined function or
  macro.  (The ninth rule is the one that refers to DEFSETF and
  DEFINE-SETF-METHOD; the other rules listed are the ones that list
  specific built-in functions).  The effect of this change is that SETF
  methods defined for global functions are ignored when there is a local
  function binding; instead, the function named (SETF reader), which may
  have a local function binding, is called.  This change is most useful
  in connection with item 4, but does not actually depend on it.

  11. Clarify that the eighth rule for SETF places (the one for macros)


  This extends the new feature throughout the language, in order to make
  things generally more consistent and powerful.  Point by point:

  1,2,3 - one should be able to compile, examine, and make declarations
  about functions regardless of whether they are named with symbols or
  with lists.

  4 - locally defined non-generic SETF functions are a logical companion
  to locally defined generic SETF functions, which can be defined with
  GENERIC-FLET or GENERIC-LABELS.  They make sense on their own, since one
  might define a local reader function and want a local writer function
  to go with it.

  5,6 - one should be able to apply development tools to functions
  regardless of how they are named.  The function DOCUMENTATION was already
  updated to work for function-names by 88-002R.  There might be some
  difficulty with implementation-dependent syntax extensions to TRACE and
  UNTRACE conflicting with this new syntax.

  7 - this restores consistency between the FUNCTION special form and the
  first element of a function call form.

  8 - it seems more consistent to allow macros to be named the same way
  that ordinary functions are named.  However, this might be considered
  redundant with DEFSETF.

  9 - this is not needed by the "chapter 1 and 2" level of CLOS, but might
  be used by the metaobject based implementation of ENSURE-GENERIC-FUNCTION.

  10 - this change was in SETF-FUNCTION-VS-MACRO and makes item 4 more useful.

  11 - this change was in SETF-FUNCTION-VS-MACRO and is a good idea, but
  actually is independent of everything else being proposed here.


;This is an example of the sort of syntax 88-002R allows
(defmethod (setf child) (new-value (parent some-class))
  (setf (slot-value 'child parent) new-value)
  (update-dependencies parent)
(setf (child foo) bar)

;If SETF of SUBSEQ was not already built into Common Lisp,
;it could have been defined like this, if the MEDIUM or LARGE
;proposal is adopted.
(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))))

;The preceding example would have to be defined like this
;if only the SMALL proposal is adopted.  This is a method
;all of whose parameter specializer names are T.
(defmethod (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, showing a locally defined setf function
(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))))

;get-setf-method could implement setf functions by calling
;this function when the earlier rules do not apply
(defun get-setf-method-for-setf-function (form)
  (let ((new-value (gensym))
	(temp-vars (do ((a (cdr form) (cdr a))
			(v nil (cons (gensym) v)))
		       ((null a) v))))
    (values temp-vars
	    (cdr form)
	    (list new-value)
	    `(funcall #'(setf ,(car form)) ,new-value ,@temp-vars)
	    `(,(car form) ,@temp-vars))))

Current practice:

  No implementation supports exactly what is proposed.  Symbolics Genera
  and the TI Explorer support something close to the MEDIUM proposal, but
  differing in a number of details.  Symbolics Genera supports items 1, 2,
  3, 6, and 11, and modified forms of items 5 and 8, of the LARGE proposal.
  Moon considers this proposal's variations from Symbolics current practice
  to be an improvement, although incompatible in some cases.
  Many implementations currently support only symbols as function names.

  Symbolics Genera and the TI Explorer have some additional function-name

Cost to Implementors:

  The SMALL and MEDIUM proposals are estimated to be no more than 50 lines
  of code and require no changes to the "guts" of the interpreter and
  compiler.  Most of the code for this can be written portably and was
  shown on two slides at the X3J13 meeting.

  Some of the changes in the LARGE proposal are trivial, some require
  the compiler to use EQUAL instead of EQ to compare function names, and
  items 4, 7, and 8 might require a more substantial implementation
  effort.  Even that effort is estimated to be negligible compared to
  the effort required to implement CLOS.

Cost to Users:

  No cost to users, other than program-understanding programs, since this
  is an upward compatible addition.

  As with any language extension, some program-understanding programs may
  need to be enhanced.  A particular issue here is programs that assume
  that all function names are symbols.  They may use GET to access
  properties of a function name or use EQ or EQL (perhaps via MEMBER or
  ASSOC) to compare function names for equality.  Such programs will need
  improvement before they can understand programs that use the new feature,
  but otherwise they will still work.

Cost of non-adoption:

  We would have to make some other language change since the language
  became inconsistent when 88-002R was adopted.

Performance impact:

  This has no effect on performance of compiled code.  It might slow
  down the compiler and interpreter but not by very much.


  CLOS will work as designed.


  Some people dislike using anything but symbols to name functions.
  Other people would prefer that if the change is to be made at all,
  the LARGE proposal be adopted so that the language is uniform in its
  treatment of the new extended function names.  Other proposals for
  how to deal with SETF in CLOS were considerably less esthetic,
  especially when package problems are taken into account.
  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, if setf
  functions are stressed over setf macros, SETF will be much easier to


  Moon supports at least FUNCTION-NAME:MEDIUM.  He does not necessarily
  approve of all parts of FUNCTION-NAME:LARGE.