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