5
$\begingroup$

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.

$\endgroup$
  • 1
    $\begingroup$ Just a side note, Evaluate is too deep in Set to work, isn''t it? $\endgroup$ – Kuba Sep 11 '17 at 7:21
  • $\begingroup$ @Kuba oh true. Nice of Mathematica to support that syntax anyway... $\endgroup$ – b3m2a1 Sep 11 '17 at 7:23
  • $\begingroup$ @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. $\endgroup$ – b3m2a1 Sep 11 '17 at 7:33
6
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – b3m2a1 Sep 11 '17 at 7:25
  • $\begingroup$ If the LHS of Set evaluated freely then after a=1, a=2 could not work because it would transform to 1=2. $\endgroup$ – Szabolcs Sep 11 '17 at 7:27
  • $\begingroup$ 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? $\endgroup$ – b3m2a1 Sep 11 '17 at 7:28
  • 1
    $\begingroup$ @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. $\endgroup$ – Leonid Shifrin Sep 11 '17 at 21:40
  • $\begingroup$ @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. $\endgroup$ – b3m2a1 Sep 11 '17 at 21:51

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.