Confusion about HoldFirst attribute of Set
The problem is not related to Set
in general but to how Set
works with Part
on a left hand side.
Following Set::setps
message documentation
This message is generated when a part assignment is used for the value of an expression other than a symbol.
Part assignments are implemented only for parts of the value of a symbol.
Shortly
Part[(*something*), (*spec*)] = (*value*)
will only work if (*something*)
is a symbol so that Set
can do in place modification of a part of that symbol. ( how much 'in place' is that is a different topic and I'm not competent to elaborate)
The second example is not a Part assignment, because the head of the lhs is not Part
but whole expression: Part[{f, g}, 1]
.
HoldFirst
does not mean it will not be evaluated ever. It is used by Set
to detect e.g. whether it is an event of a Part assignment.
Kuba's answer explains why the first form does not work, but it does not address why the second form does work. That has been discussed in other questions
- DownValue assignment using Apply
- Why is the first argument of the SetDelayed evaluated?
- https://stackoverflow.com/q/5846756/618728
- https://stackoverflow.com/q/7408310/618728
One can see that the head of the left-hand-side is evaluated in each of these cases:
ClearAll[a, b, c, x]
x = {a, b, c};
(# & @@ x)[1] = 1;
Extract[x, 2][1] = 2;
Last[x][1] = 3;
Definition[a, b, c]
a[1] = 1 b[1] = 2 c[1] = 3
Additionally the arguments are evaluated as seen in:
pats = {i_, j_, k_};
Last[x][First[pats]] = i^2;
c[4]
16
The LHS is not fully evaluated before assignment however; instead a special evaluation sequence is used.
With the definitions above in place if one separately evaluates:
Last[x][Last@pats]
k_^2
And if one manually attempts assignment to this it does not work:
k_^2 = 4;
Set::write: Tag Power in k_^2 is Protected. >>
However assigning to the compound expression:
Last[x][Last@pats] = 5;
c[1000]
5
? c
c[1] = 3 c[k_] = 5