# Wrapping an association with a specialization of the buildin Set (=) function?

I want to wrap some association data into a dedicated symbol (S by example)

S /: S[a_Association][k_] := a[k]
S /: Format[s_S] :=
"Demo, here are my keys " <> ToString[Keys[First[s]]]


I use such approach (but AFAIK this is a common one) as I see two benefits:

1/ easy argument filtering

foo[S[a_Association]]:="Hello S!"


2/ syntaxic & looks sugar:0

s = S[<|"A" -> 1, "B" -> 2|>]
s["A"]


prints:

"Demo, here are my keys {A, B}"
1


However when you have a nice syntax for s["A"], you also want a nice syntax for s["A"]=3. This is even mandatory, as

s["A"]=3


It does not change the internal association:

s // First


<|"A" -> 1, "B" -> 2|>

but only binds 3 to s["A"]:

s["A"]

3


So far my solution to the problem is to modify the buildin Set function as follows:

Unprotect[Set]
Set[s_Symbol[k_], v_] /; MatchQ[Hold[s] /. OwnValues[s], Hold[_S]] :=
Block[{a = First[s]}, a[k] = v; Set[s, S[a]]]
Protect[Set]


Now

s["A"]=3
s["C"]=4
s // First


prints

"Demo, here are my keys {A, B}"
"Demo, here are my keys {A, B, C}"
<|"A" -> 3, "B" -> 2, "C" -> 4|>


as expected.

My question:

• Redefining Set like this is really a last resort and is best avoided. There are alternative ways (@Kuba provided references to such). – Leonid Shifrin Jun 19 at 19:00
• I have discussed the issues associated with Set overloading here, so I refer you to that discussion for arguments against it. Also check out this question. None of those discussions will likely have a direct answer to your question, but the references provided by @Kuba should point you to the better direction. – Leonid Shifrin Jun 19 at 21:25