[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: SYMBOL-FUNCTION
Date: Thu, 10 Apr 86 23:05:47 pst
From: hpfclp!diamant@hplabs.ARPA
To: common-lisp@su-ai.ARPA
Subject: Re: EVAL-WHEN (really symbol-function)
I think it is time we back off for a second from what is in the book, and
just think about what makes sense for Common LISP. I would advocate
making the restriction I have suggested explicit: "It is an error to
setf the symbol-function to an object not of type FUNCTION." Also, the
Yes, I agree that we should restrict what can be assigned to
SYMBOL-FUNCTION, but it cannot be based on the the type FUNCTION as it
is currently defined, since (FUNCTIONP 'CAR) is true. This would
allow (SETF (SYMBOL-FUNCTION 'FOO) 'CAR), which is what we are trying
to prevent.
I propose that we adopt the distinction between a FUNCTION OBJECT
and a FUNCTION NAME mentioned on pg. 59. By this
definition, lambda-expressions and symbols would be FUNCTION NAMES,
but NOT function objects (this restriction is mine, pg. 59 would need
to be 'clarified' :->). Compiled-code objects and closures would be
the ONLY CL defined FUNCTIONS (i.e., FUNCTION DEFINITIONS or FUNCTION
OBJECTS). (Cf. pg 89 for explanation of why closures are sufficient
for all uncompiled functions).
Thus type FUNCTION would have two subtypes (not necessarily disjoint
in all implementations, since some might use lambda-expressions as
function objects): FUNCTION-NAME and FUNCTION-OBJECT (I would prefer
to call it FUNCTION-DEFINITION so we wouldn't have to say things like
"an object of type function-object").
If the value to be assigned to SYMBOL-FUNCTION is a FUNCTION-NAME
(note that this test should be done first), then the FUNCTION OBJECT
that it NAMES is assigned (and it is an error if the NAME does not
name a function object (which can happen only with symbols). In the
case of a lambda-expression, this means that the implementation turns
it into a closure or a compiled-code object. Note that the following
two assignments would still be quite different:
(let ((x 1))
(setf (symbol-function 'foo) '(lambda () x)) ; x is implicitly special
(setf (symbol-function 'foo) #'(lambda () x))) ; x is lexical
In the case of a symbol (e.g., FOO) that names a FUNCTION OBJECT, it would be
undefined whether or not
(eql (symbol-function 'foo)
(symbol-function (prog1 'bar (setf (symbol-function 'bar) 'foo))))
Also, note that
(setf (symbol-function '<<symbol>>) '<<function-name>>)
would be unusual among SETFs in that the value returned by the setf
would not be EQL to the value subsequently returned by the accessor
form.
Such a definition would also clear up the definition of FUNCTION. The
arg. to function must be a FUNCTION-NAME and the result will be a
FUNCTION-OBJECT. It would also clear up APPLY and FUNCALL. The first
arg. to both functions must be of type FUNCTION. In the case of a
FUNCTION-OBJECT, it is 'used' directly. In the case of a
FUNCTION-NAME, the FUNCTION-OBJECT that it names will be 'used'.
This will also clear up wording like "The argument...should be a
function...in a form acceptable to the FUNCTION special form" (pg.
314). Instead, we merely say, "The argument must be a function name."
implementation should be at liberty to store the functional interpretation
of a lambda or symbol if that is what setf is given. Note that this
doesn't restrict the implementation from setting it in the case of a macro
or special form. My real concern is that no gain is made by making
the function cell completely general, and there are some losses (consistency
with (setf (macro-function...)) and performance). It seems every time
we get into a discussion about an ambiguity, we always make a change that
tends to make the language more complicated. Why can't we try for simplicity
this time (I really don't see that we are losing anything)?
All this hidden hash concept does for you is give the user one function cell
and the implementation an other one. What good is the user function cell if
the system isn't even using it?
If anybody has a reason why the restriction I mention above interferes with
execution of correct code, please say so (don't tell me about doing an
EQL test before and after a (setf (symbol-function...)) because that is what
we are disputing. I mean when would someone legitimately write a piece of
Common LISP with non-function items in the function cell (unless they
were simply using it as a value cell)? Until someone can generate such an
example, I see no reason why some people are so tenaciously insisting that
anything can be stored in the funtion cell.
If I directly assign a function object using (SETF (SYMBOL-FUNCTION...)...),
I would like it guaranteed that (SYMBOL-FUNCTION...) return the EQL
function object (not that this definitely does not hold for names).
In trace packages, encapsulations, etc., the program putting in a
wrapper may need to know if the current function definition for a
symbol is EQL to the one it SETF in there. My proposal allows this.
Consider what happens if you allow arbitrary objects in the function cell
as in the following example:
(setf x '(lambda () "Hi"))
(setf (symbol-function 'y) x)
(setf (third x) "Bye")
(y)
What is this supposed to return? In an implementation which guarantees that
Under my proposal, it would be undefined, since an implementation is
free to use the lambda-expression directly, closure it, compile it, or
just copy it.
-- Nick