9

Let's say I want to track any assignment attempt for a variable a:

a /: Set[a, x_] := Print@{a, x}

This works as intended:

a = 5
(* {a,5} *)

a
(* a *)

However, this doesn't catch the {...}={...} syntax:

({a, b} = {1, 2})
(* {1, 2} *)

a
(* 1 *)

And the following obviously does not work:

a /: Set[{___, a, ___}, x_] := Print@{a, x}
TagSetDelayed::tagpos: Tag a in {___, a, ___} = x_ is too deep for an assigned rule to be found.
(* $Failed *)

This leads to the following two questions:

  • Is there any way to "nice" way to achieve such functionality? (By "nice" I mean something similar to assigning the definition to the upvalues of a, as opposed to e.g. Unprotecting List/Set and attaching the definition there)
  • Why does Set not simply "thread" over the lists to give upvalue definitions a chance to catch the assignment? As it stands, this potentially breaks many "smart" symbols (e.g. file backed symbols) if the user ever decides to use the list assignment syntax. Is there anything what would not work if this would be the case?
Lukas Lang
  • 33,963
  • 1
  • 51
  • 97
  • Would you say this a duplicate of this? As Szabolcs points out there for a similar problem, that threaded Set is probably internal. There are a few ways you could work around this, depending on what you need done, but none that use exactly this syntax, I think. – b3m2a1 Sep 18 '17 at 23:02
  • That question is surely related, but I think this one is different enough. Here I ask for a workaround of this particular problem and a reason why this behavior was chosen, while the other one is more concentrated on why this happens. – Lukas Lang Sep 19 '17 at 13:38
  • If you just need to know that an assignment was attempted, and not the value of the assignment, you could just do Protect[a]. – Carl Woll Sep 19 '17 at 14:56

0 Answers0