# Side-effecting an array in an association?

I'm working on some classical data structures (stack, queue, etc.) and want to mimic oo style in MMA. As a first attempt, I want to store an array in an Association, like this:

q = <|elems -> ConstantArray[Null, 4]|>

<|elems -> {Null, Null, Null, Null}|>


Later, I want to side-effect my array, like this

q[elems][[2]] = 42;


Set::setps: q[elems] in the part assignment is not a symbol. >>

Ahh, yes, of course, I need a symbol... Next attempt is this:

q = Module[{storage = ConstantArray[Null, 4]},
<|elems -> Hold[storage]|>]

<|elems -> Hold[storage\$1987]|>

In[4]:= ReleaseHold[q[elems]][[2]] = 42


During evaluation of In[4]:= Set::setps: ReleaseHold[q[elems]] in the part assignment is not a symbol. >>

 42


Oh, yeah, that's not going to work.

I could do the following, but it's going to copy the array every time and defeat the purpose of implementing classical algorithms (that being "efficiency"):

q = <|elems -> ConstantArray[Null, 4]|>;
SetAttributes[setQ, HoldFirst];
setQ[q_, slot_, item_] :=
Module[{newElems = q[elems]},
newElems[[slot]] = item;
q[elems] = newElems;
q[elems]];
setQ[q, 2, 42]

{Null, 42, Null, Null}


It looks like I need some kind of variant of Part that doesn't evaluate a held symbol on its left-hand side -- a PartHoldFirst. I don't see a way to do this with stuff I know.

Maybe I don't understand what you're trying to do, but...

q = <|elems -> ConstantArray[Null, 4]|>

q[[1, 2]] = 42;

q

<|elems -> {Null, 42, Null, Null}|>

q[[Key[elems], 4]] = 99;

<|elems -> {Null, 42, Null, 99}|>


So whether you set by position or Key it works.

• Interesting -- you can index into Associations with Part (double brackets) & Key (for non-string keys) as well as with single-brackets, function-call notation, and then you can continue to index into them with commas in the double brackets, similarly to levels in ordinary lists. I hadn't appreciated this fact deeply enough. Aug 17 '14 at 13:07
• A bigger question is "why have the function-call notation at all?" It seems the double-bracket does at least as much, plus it obviously does much more, enabling whole scenarios like oop-emulation. Aug 17 '14 at 13:25
• Another implication of positional notation is that order does matter, that, intentionally, <|a->1,b->2|>=!=<|b->2,a->1|> but Sort[<|a->1,b->2|>]===Sort[<|b->2,a->1|>]. I sometimes wonder how web programmers deal with the fact that determining equality of two JSON objects without a canonical ordering on keys is combinatorial in the number of keys. Maybe JSON objects have a canonical ordering on keys. Aug 17 '14 at 13:51
• I found out something that functional notation [...] can do and that part notation [[...]] can't do: side-effectfully add a key. Let t = <|"a"->1|>, then t[["b"]]=2 succeeds and produces 2, but t is still <|"a"->1|>. Now t["b"]=2 succeeds and produces 2, but t is now modified and equals <|"a"->1, "b"->2|>. Aug 19 '14 at 2:06
• @Reb Thanks for the note. Aug 19 '14 at 4:44

I had a flash of insight and did the following. Notice particularly the necessary RuleDelayed on the elems tag in the association:

q = Module[{storage = ConstantArray[Null, 4]},
<|elems :> storage, set -> ((storage[[#1]] = #2) &)|>];
q[set][2, 42];
q[elems]

{Null, 42, Null, Null}