I've seen some posts about mutable objects in WL and some implementations:

Many of these questions are about OOP or some class inheritance framework for dealing with objects. My question is simpler. Is there a performant and simple way to define an object that can be mutated? No classes, no methods, etc.

The closest thing that comes to my mind are Associations that are stored in a variable:

In[]:= assoc = <|"AC" -> 0, "RAM" -> {0, 0, 0, 0}|>;

In[]:= assoc["AC"] = 4
Out[]= 4

In[]:= assoc
Out[]= <|"AC" -> 4, "RAM" -> {0, 0, 0, 0}|>

x["key"] = val is what I want to see in my code.

The problem with the above association is the following:

In[]:= assoc["RAM"][[1]] = 4
During evaluation of In[]:= Set::setps: assoc[RAM] in the part assignment is not a symbol.
Out[]= 4

I understand why that fails, but to me there should be a way to write code like that.

I know there are mutation handlers that I could use to somewhat make it work (https://mathematica.stackexchange.com/a/165910/59240), but the thing about associations is that they are as fast as WL will go, and I want that performance.

I tried DataStructures, the problem is that the code becomes less readable:

assoc2 = <|"AC" -> CreateDataStructure["Counter", 0], "RAM" -> CreateDataStructure["FixedArray", {0, 0, 0, 0}]|>;

In[]:= assoc2["AC"]["Set", 4]
Out[]= 4

In[]:= assoc2["RAM"]["SetPart", 1, 4]
Out[]= 4

Of course that is up to debate. Perhaps the solution is that Set should work on DataStructure["Counter", ...] and Set + Part on "FixedArray", e.g. assoc2["RAM"][[1]] = 4.

Another issue when dealing with DataStructures is how they interact with Dynamic and the Front End:

In[]:= counter = CreateDataStructure["Counter", 0];

In[]:= Dynamic[counter["Visualization"]]
(* Out[]= <- Graphics -> *)

In[]:= counter["PreIncrement"]
Out[]= 1

The visualization won't update because the FE has no idea if the contents of the DS changed. There might be ways to overcome this but all seem overcomplicated.

There might not be a definite answer, but hopefully some ideas can be shared.


Edit 1:

This works :) :

In[]:= assoc[["RAM", 1]] = 4
Out[]= 4
  • 5
    $\begingroup$ Just use Part: a=<|"a" -> 0, "b" -> {0, 0, 0, 0}|>;a[["b", 1]]=2;a $\endgroup$
    – M.R.
    Commented Sep 29, 2021 at 3:17
  • $\begingroup$ Or AssociateTo[assoc, "AC" -> 4]. $\endgroup$ Commented Sep 29, 2021 at 13:12
  • 1
    $\begingroup$ Expr bags might be adequately performant. See also this MSE thread for improving performance. $\endgroup$ Commented Sep 29, 2021 at 14:04
  • 3
    $\begingroup$ PS Why the close votes? $\endgroup$ Commented Sep 29, 2021 at 14:06


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.