# Set on symbol with OwnValues skips UpValues

Can anyone provide insight on what's going on here?

First I define a new Set behavior for a symbol:

mySym /: Set[mySym[f_], v_] := v

mySym[1] = 2

(* Out *) 2

mySym[1]

(* Out *) mySym[1]


Works great

But if we provide an alias for this symbol the UpValues never get called:

ms = mySym;

ms[1] = 2

(* Out *) 2

mySym[1]

(* Out *) 2


Even more, if we pre-Evaluate that ms we still have an issue:

Evaluate[ms][1] = 3

(* Out *) 3

mySym[1]

(* Out *) 3


Although With does the appropriate thing:

With[{m = ms},
m[1] = 4
]

(* Out *) 4

mySym[1]

(* Out *) 3


What's the cause of that? It's single-handedly nixed an OO implementation I was working on.

• Just a side note, Evaluate is too deep in Set to work, isn''t it?
– Kuba
Sep 11, 2017 at 7:21
• @Kuba oh true. Nice of Mathematica to support that syntax anyway... Sep 11, 2017 at 7:23
• @Kuba one thing worth noting is that this syntax is supported: Evaluate@Symbol["sym"][1] = 1 which is what made me think the other should work. Sep 11, 2017 at 7:33

But if we provide an alias for this symbol the UpValues never get called:

Set is HoldFirst. That means that its first argument does not get evaluated before it is passed to Set. ms[1] = 2 never gets transformed to mySym[1] = 2.

It is true that internally Set will examine its first argument and will evaluate it sometimes. That is why in this case the definition mySym[1] = 2 gets created. But that happens internally within Set. The expression mySym[1] = 2, which could trigger the UpValues rule, never materializes.

Even more, if we pre-Evaluate that ms we still have an issue:

Evaluate works only at level 1 within a held expression.

Hold[Evaluate[1 + 1]]
(* Hold[2] *)

Hold[{Evaluate[1 + 1]}]
(* Hold[{Evaluate[1 + 1]}] *)


Whenever the evaluator encounters a symbol with a Hold* attribute, it will check for any Evaluate within the first level only, and act accordingly.

• Yeah the Evaluate was just confusion on my part. The fact that ms never gets transformed to mySym but mySym still gets the OwnValue is slightly confusing, honestly. That this fails is well known: a = 1; a[2] = 3. But that the OwnValues replacement never happens is odd. Certainly a "gotcha" that's a bit hard to debug around. Sep 11, 2017 at 7:25
• If the LHS of Set evaluated freely then after a=1, a=2 could not work because it would transform to 1=2. Sep 11, 2017 at 7:27
• Good point. I'd honestly almost prefer no evaluation than occasional internal evaluation though. But I'm sure there's a design reason for it. Also do you know why the Evaluate syntax is supported? Is it for things like this: Evaluate@Symbol["s"] = 1? Sep 11, 2017 at 7:28
• @b3m2a1 "Also do you know why the Evaluate syntax is supported?" - This is not like some special "syntax" is supported. Set is HoldFirst, and as such, obeys the standard evaluation semantics of HoldFirst attribute in Mathematica - in particular that Evaluate can override it. There is no special rule added for Set to make Evaluate work - it follows from the general evaluation semantics of the language. Sep 11, 2017 at 21:40
• @LeonidShifrin the oddity for me is/was that things like Evaluate[Symbol["sym"]][1] = 1 worked, but then I found out that Symbol["sym"][1] = 5 works, although Symbol["sym"] = 5 does not, so maybe it's just ignoring the Evaluate there. The skipping of the UpValues just threw me for a loop. Sep 11, 2017 at 21:51