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

Re: issue FUNCTION-TYPE



A couple of concerns:

It seems to me that the combination of #2e:
  ... the functions FUNCALL and APPLY ... will accept any object that
  can be coerced to a FUNCTION ...
and #6a:
  (COERCE symbol 'FUNCTION) extracts the symbol-function of the
  given symbol, signalling an error if SYMBOL is not fbound or if
  the contents of the symbol-function cell is not a procedure.
requires implementations to signal errors for any undefined symbol.
I don't think the standard should require such error checking, for
reasons of efficiency in some implementations.  (Of course it should
be encouraged.)

Perhaps the reason for this language is that COERCE is expected to
signal an error.  That may be another issue; but for this issue I
don't think we should imply COERCE is actually used for every FUNCALL
or APPLY.


The other concern I had was that unlike the earlier FUNCTION-TYPE:
STRICT-REDEFINITION proposal, both symbols and lambda-expressions
(i.e., lists whose car is LAMBDA and whose cadr is a list) are
assumed to be acceptable to FUNCALL or APPLY.  I had thought that
at the meeting we had agreed that #2e should refer to whatever
coerceable to a FUNCTION, but that what was coerceable was still
an issue.

In particular, I'd very much like to see lists not be FUNCALLable or
APPLYable.  I think there are too many aesthetic and efficiency
reasons against continuing to allow lambda-expressions be treated as
"functions".

So far I haven't seen some of those reasons written down.

Here's an aesthetic/counter-intuitive-to-the-novice one:
Lambda-expressions don't obey the normal, apparent scoping rules because
free variables can't refer to lexical bindings.  This is because
coercing a list to a function means (EVAL `(FUNCTION ,list)).

The following code does -not- count the number of nodes in a graph:
  ...
  (let ((counter 0))
    (traverse-thing '(lambda (node) (incf counter))
                    (thing-root)))
  ...
since it is not the same as
  ...
  (let ((counter 0))
    (traverse-thing #'(lambda (node) (incf counter))
                    (thing-root)))
  ...
which does pass around a closure incrementing the LET variable.
(This assumes COUNTER wasn't DEFVAR'd.)

Here's an efficiency reason:
At run-time FUNCALL or APPLY must check to see if its first argument
is a list, so that it can decide to call EVAL (or internal-equivalent).
In some implementations, this is deemed to be too expensive.

Of course some implementations may decide to handle lists for
compatibility reasons.

Anyway, these kinds of arguments really ought to be in this proposal
so everyone is aware of the issues.  I'd rather make sure this proposal
resolves the question than postpone it with yet another proposal,
especially since that was what the original proposal was about.

			---Walter
------