In languages that don't support optional parameters directly, programmers typically find ways to simulate them. One technique is to use distinguished 'no-value' values that the caller can pass to indicate they want the default value of a given parameter. In C, for example, it's common to use NULL
as such a distinguished value. However, such a protocol between the function and its callers is ad hoc—in some functions or for some arguments NULL
may be the distinguished value while in other functions or for other arguments the magic value may be -1 or some #defined
constant.
59
The constant CALL-ARGUMENTS-LIMIT
tells you the implementation- specific value.
60
Four standard functions take both &optional
and &key
arguments—READ-FROM- STRING
, PARSE-NAMESTRING
, WRITE- LINE
, and WRITE-STRING
. They were left that way during standardization for backward compatibility with earlier Lisp dialects. READ-FROM- STRING
tends to be the one that catches new Lisp programmers most frequently—a call such as (read-from-string s :start 10)
seems to ignore the :start
keyword argument, reading from index 0 instead of 10. That's because READ-FROM-STRING
also has two &optional
parameters that swallowed up the arguments :start
and 10.
61
Another macro, RETURN
, doesn't require a name. However, you can't use it instead of RETURN-FROM
to avoid having to specify the function name; it's syntactic sugar for returning from a block named NIL
. I'll cover it, along with the details of BLOCK
and RETURN-FROM
, in Chapter 20.
62
Lisp, of course, isn't the only language to treat functions as data. C uses function pointers, Perl uses subroutine references, Python uses a scheme similar to Lisp, and C# introduces delegates, essentially typed function pointers, as an improvement over Java's rather clunky reflection and anonymous class mechanisms.
63
The exact printed representation of a function object will differ from implementation to implementation.
64
The best way to think of FUNCTION
is as a special kind of quotation. QUOTE
ing a symbol prevents it from being evaluated at all, resulting in the symbol itself rather than the value of the variable named by that symbol. FUNCTION
also circumvents the normal evaluation rule but, instead of preventing the symbol from being evaluated at all, causes it to be evaluated as the name of a function, just the way it would if it were used as the function name in a function call expression.
65
There's actually a third, the special operator MULTIPLE-VALUE-CALL
, but I'll save that for when I discuss expressions that return multiple values in Chapter 20.
66
In Common Lisp it's also possible to use a LAMBDA
expression as an argument to FUNCALL
(or some other function that takes a function argument such as SORT
or MAPCAR
) with no #'
before it, like this:
(funcall (lambda (x y) (+ x y)) 2 3)
This is legal and is equivalent to the version with the #'
but for a tricky reason. Historically LAMBDA
expressions by themselves weren't expressions that could be evaluated. That is LAMBDA
wasn't the name of a function, macro, or special operator. Rather, a list starting with the symbol LAMBDA
was a special syntactic construct that Lisp recognized as a kind of function name.
But if that were still true, then (funcall (lambda (...) ...))
would be illegal because FUNCALL
is a function and the normal evaluation rule for a function call would require that the LAMBDA
expression be evaluated. However, late in the ANSI standardization process, in order to make it possible to implement ISLISP, another Lisp dialect being standardized at the same time, strictly as a user-level compatibility layer on top of Common Lisp, a LAMBDA
macro was defined that expands into a call to FUNCTION
wrapped around the LAMBDA
expression. In other words, the following LAMBDA
expression:
(lambda () 42)
exands into the following when it occurs in a context where it evaluated:
(function (lambda () 42)) ; or #'(lambda () 42)
This makes its use in a value position, such as an argument to FUNCALL, legal. In other words, it's pure syntactic sugar. Most folks either always use #' before LAMBDA expressions in value positions or never do. In this