The S evaluation model for function calls is unusual in that arguments
are evaluated during evaluation of the body of the called function,
not before the call, and then only when the value is really
needed.
Argument evaluation is described on pages 181-183 of
"Programming with Data"; in particular, page 182 describes when the
actual evaluation takes place;
roughly, when using an interface to C, etc.,
when copying as for a local assignment, and when looking for a method.
For the first two cases, a missing with no default produces an
error then, but not before. For method search, class
"missing"
is legitimate in a signature, and not an error.
It might not be obvious, to say the least, what are all the consequences of lazy evaluation. There are some examples in the book that illustrate useful cases of allowing missing arguments. Also, other examples can arise in which there are two possible expressions, supplied as two arguments, but with the understanding that the called function will choose only one of these to evaluate.
As yet another variant, consider the following fragment. It's useless
as is, but meant to illustrate another possible technique with lazy
evaluation.
Function b
passes its argument to function
a
, but doesn't want to call a
with no
arguments if its own argument is missing.
Instead it computes a flag to warn a
not to use the
argument.
> b = function(x) a(x, missing(x)) > a = function(y, useDefault) if(missing(y) || useDefault) 0 else x > b(1) [1] 1 > b() [1] 0Obviously, this is trivial as it stands, but embedded into a more elaborate context it might be a convenient simplification of the design of
b
.
One natural confusion might be to think that missing(y)
is TRUE
in the body of a
.
But this is not what's happening: the argument to a
is
never missing in the call from b
.
What the object passed to a
actually is, on the
other hand, we should never know or care.
A subtle implementation detail is that the S evaluator has to handle such situations by checking the actual object reference (to use Java terminology) rather than the contents of the object. Generally, one can't say in a language like S that any actual object is "not an object"; you get into some impossible circularity when you try to apply that idea in general.
In the example above, doing anything much other than
missing(y)
to the argument is going to generate an error
(effectively preventing you from peeking at the actual object passed
down).
The reason is not a problem in a
, but rather that
evaluating the argument there requires evaluating the argument in
b
, which is missing with no default. Hence the error
message below.
> b = function(x)a(x) > a = function(y)class(y) > b(pi) [1] "numeric" > b() Problem in b(): argument "x" is a missing with no default