14
$\begingroup$
In[1]: f=g;
In[2]: SetDelayed[f[x_],x^2];
In[3]: ?f
Global`f
f=g
In[4]: ?g
Global`g
g[x_]:=x^2

However, SetDelayed has the property of HoldAll. It seems to me the first argument f[x_] should not be evaluated to g[x_]. Why is this not so?

The same thing happens for Set which has a HoldFirst attribute.

Thanks

$\endgroup$
  • $\begingroup$ Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. $\endgroup$ – bbgodfrey Sep 26 '15 at 15:16
  • $\begingroup$ Because HoldAll is documented to not do nothing, but something. If you do SetDelayed[Unevaluated[f][x_], x^2]; you will get what you want. $\endgroup$ – Rolf Mertig Sep 26 '15 at 16:04
  • 4
    $\begingroup$ I have a rather detailed discussion of evaluation during assignments here. Basically, HoldAll simply means that arguments are passed to the function in unevaluated form, but does not restrict what functions decide to do with them. And Set and SetDelayed do evaluate their first arguments, albeit in a special way. An example very similar to yours I also considered in this answer, in the section named "Evaluation: OwnValues". $\endgroup$ – Leonid Shifrin Sep 26 '15 at 16:20
  • $\begingroup$ Check out the updated answer. I believe this is the reason behind the design. $\endgroup$ – Szabolcs Sep 29 '15 at 10:32
  • 1
    $\begingroup$ @Szabolcs This is one of them. Another one, which is IMO no less important, is that keeping l.h.s. entirely unevaluated would often lead to discrepancy between l.h.s. in definition and actual l.h.s. of a typical function call involving a given symbol, in case if such l.h.s. evaluates non-trivially - because otherwise in one case, it would evaluate, and in the other, it wouldn't. In other words, the current policy tries to make evaluation during function calls be maximally consistent with evaluation during assignments. $\endgroup$ – Leonid Shifrin Sep 29 '15 at 12:41
10
$\begingroup$

I will interpret the question "Why?" to be asking

What useful purpose does it serve that SetDelayed evaluates its first argument?

In the standard evaluation sequence, the evaluation of f[x] begins with evaluating the head f. Thus if f = g, then f[x] first evaluates to g[x]; then any definitions of g would be applied. If SetDelayed did not evaluate f[x_], then it would create a definition that is not (conveniently) reachable.

One can still create a definition for the symbol f, though not "conveniently," using DownValues. For example,

DownValues[f] = {HoldPattern[f[x_]] :> x^2}

? f

Mathematica graphics

But f still evaluates to g first:

f[x]
(*  g[x]  *)

If you Unset the own-value for f, then the definition in DownValues will be applied:

f =.
f[x]
(*  x^2  *)
$\endgroup$
7
$\begingroup$

tldr: a holding attribute just means that, if the code is reasonable, the evaluation is non-standard, but doesn't mean there's no evaluation.

The attribute HoldAll and his holding friends only mean there is no automatic guaranteed standard evaluation taking place. Evaluation might still happen if it was manually coded that way. For example

SetAttributes[f, HoldAll];
f[x_] := Hold[Evaluate[x]];

This would be unreasonable code, sure: why would you give f a holding attribute only to force it to evaluate as usual? BUT, possible.

In the case of SetDelayed and others, the evaluation that happens isn't the standard one. For example, after doing x={1,2,3};, runinng x[[2]]=4; should not evaluate to 2=4. After doing g[x_] := x^2;, running g[2]:=6; should not evaluate to 4:=6. But heads and arguments, when the left hand side is of the form _[___], are. This non-standard evaluations can only be achieved by turning automatic evaluation off and then evaluating what you want by hand.

$\endgroup$
  • $\begingroup$ I cannot help but notice that you have been inactive for nearly a year. I have always valued your contributions and I hope to see you posting again soon. $\endgroup$ – Mr.Wizard Aug 2 '16 at 8:42
  • 2
    $\begingroup$ Thanks @Mr.Wizard, nice to hear. Hopefully I'll become somewhat active in a few months $\endgroup$ – Rojo Aug 4 '16 at 13:12
6
$\begingroup$

Another answer to

What useful purpose does it serve that SetDelayed evaluates its first argument?

is that it's convenient with patterns and optional arguments.


Example with user-defined patterns:

acceptedSymbolsPattern = One|Two|Three;
f[acceptedSymbolsPattern] = True;
f[_] = False;

f[One]
(* True *)

f[12]
(* False *)

In some cases you might want to define pieces of patterns that can be re-used several times in different contexts. I believe this is the main reason why the LHS is evaluated for non-OwnValue assignments.


Example with optional arguments:

d = {1,2,3}
f[x_ : d] := Hold[x]

f[]
(* Hold[{1,2,3}] *)

In some cases you may want to use a default value for an optional argument that is already defined elsewhere. This behaviour make it simple to do so.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.