Delay evaluation
This functionality does not run in MATLAB.
hold(object
)
hold(object)
prevents the evaluation of object
.
When a MuPAD^{®} object is entered interactively, then the
system evaluates it and returns the evaluated result. When a MuPAD
object is passed as an argument to a procedure,
then the procedure usually evaluates the argument before processing
it. Evaluation means that identifiers are
replaced by their values and function calls are executed. hold
is
intended to prevent such an evaluation when it is undesirable.
A typical application of hold
is when a function
that can only process numerical arguments, but not symbolical ones,
is to be used as an expression. See Example 6.
Another possible reason for using hold
is
efficiency. For example, if a function call f(x, y)
with
symbolic arguments is passed as argument to another function, but
is known to return itself symbolically, then the possibly costly evaluation
of the "inner" function call can be avoided by passing
the expression hold(f) (x, y)
as argument to the
"outer" function instead. Then the arguments x,
y
are evaluated, but the call to f
is
not executed. See examples Example 1 and Example 7.
Since using hold
may lead to strange effects,
it is recommended to use it only when absolutely necessary.
hold
only delays the evaluation of an object,
but cannot completely prevent it on the long run; see Example 5.
You can use freeze
to
completely prevent the evaluation of a procedure or
a function environment.
A MuPAD procedure can be declared
with the option hold. This
has the effect that arguments are passed to the procedure unevaluatedly.
See the help page of proc
for
details.
The functions eval
or level
can
be used to force a subsequent evaluation of an unevaluated object
(see example Example 2). In procedures
with option hold
, use context
instead.
In the following two examples, the evaluation of a MuPAD expression
is prevented using hold
:
x := 2: hold(3*0  1 + 2^2 + x)
hold(error("not really an error"))
Without hold
, the results would be as follows:
x := 2: 3*0  1 + 2^2 + x
error("not really an error")
Error: not really an error
The following command prevents the evaluation of the operation _plus
,
but not the evaluation of the operands:
hold(_plus)(3*0, 1, 2^2, x)
Note that in the preceding example, the arguments of the function
call are evaluated, because hold
is applied only
to the function _plus
. In the following example, the
argument of the function call is evaluated, despite that fact that f
has
the option hold:
f := proc(a) option hold; begin return(a + 1) end_proc: x := 2: hold(f)(x)
This happens for the following reason. When f
is
evaluated, the option hold
prevents the evaluation
of the argument x
of f
(see
the next example). However, if the evaluation of f
is
prevented by hold
, then the option hold
has
no effect, and MuPAD evaluates the operands, but not the function
call.
The following example shows the expected behavior:
f(x), hold(f(x))
The function eval
undoes
the effect of hold
. Note that it yields quite different
results, depending on how it is applied:
eval(f(x)), eval(hold(f)(x)), eval(hold(f(x))), eval(hold(f))(x)
Several hold
calls can be nested to prevent
subsequent evaluations:
x := 2: hold(x), hold(hold(x))
The result of hold ( hold(x) )
is the unevaluated
operand of the outer call of hold
, that is, hold(x)
. Applying eval
evaluates
the result hold(x)
and yields the unevaluated
identifier x
:
eval(%)
Another application of eval
yields
the value of x
:
eval(%)
delete x, f:
The following command prevents the evaluation of the operation _plus
,
replaces it by the operation _mult
, and then evaluates the result:
eval(subsop(hold(_plus)(2, 3), 0 = _mult))
The function domtype
evaluates
its arguments:
x := 0: domtype(x), domtype(sin), domtype(x + 2)
Using hold
, the domain type of the unevaluated
objects can be determined: x
and sin
are identifiers,
and x + 2
is an expression:
domtype(hold(x)), domtype(hold(sin)), domtype(hold(x + 2))
hold
prevents only one evaluation of an object,
but it does not prevent evaluation at a later time. Thus using hold
to
obtain a a symbol without a value is usually not a good idea:
x := 2: y := hold(x); y
In this example, deleting the
value of the identifier x
makes it a symbol, and
using hold
is not necessary:
delete x: y := x; y
However, the best way to obtain a new symbol without a value
is to use genident
:
y := genident("z"); y
delete y:
Consider the piecewise defined function f(x) that is identically zero on the negative real axis and equal to on the positive real axis:
f := x > if x < 0 then 0 else exp(x) end_if:
This function cannot be called with a symbolic argument, because the condition x < 0 cannot be decided:
f(x)
Error: Cannot evaluate to Boolean. [_less] Evaluating: f
We wish to integrate f
numerically. However,
the numerical integrator expects
the function as an expression:
numeric::int(f(x), x = 2..2)
Error: Cannot evaluate to Boolean. [_less] Evaluating: f
The solution is to suppress premature evaluation of f
when
passing the function with a symbolic argument. Inside the numerical
integrator, numerical values are substituted for x before
the function is called and evaluated:
numeric::int(hold(f)(x), x = 2..2)
The function int
is
unable to compute a closed form of the following integral and returns
a symbolic int
call:
int(sqrt(x)*sqrt(sqrt(x) + 1), x)
After the change of variablessqrt(x)=t
,
a closed form can be computed:
t := time(): f := intlib::changevar(int(sqrt(x)*sqrt(sqrt(x) + 1), x), sqrt(x) = y); time()  t; eval(f)
Measuring computing times with time
shows: Most of the time in the call
to intlib::changevar
is
spent in reevaluating the argument. This can be prevented by using hold
:
t := time(): f := intlib::changevar(hold(int)(sqrt(x)*sqrt(sqrt(x) + 1), x), sqrt(x) = y); time()  t;

Any MuPAD object 
Unevaluated object.