1

Imagine we have the following structure (like a module)

(*separate file*)
<|
    "package"->"blabla",
    "internal parameter"->0
    "delayed action":>With[{},%["internal parameters"]=1;]
|>;

(somewhere in the code) module = Get["file_with_association_above"]; module["delayed action"]; module["internal parameter"] == 1

It would be very convenient to implement something like this, where when we call ["delayed action"] function from the association, it will modify the variable that stores this function.

However, now I got an error as expected

Set::write: Tag RuleDelayed in "delayed action":>%["internal parameters"] is Protected.

I have found that there is a function Names[], that can be used to look through all defined symbols and in the theory one can find the right variable and modify it. But, I think it would be really slow.

PS: Yes, I am looking for the analogue of @this keyword, like an object self-reference, but in the terms of Mathematica's paradigm.

Kirill Vasin
  • 1,235
  • 12
  • 14

3 Answers3

3

This is not really an answer but the comment went longer and there're problems inserting code.

I think this will be the bad idea to implement something like "self modifying associations" on the language level.

The semantics of Mathematica's data structures is generally that they are essentially immutable. There're ways to simulate object oriented programming storing values in a symbol or using handlers but I'd suggest to rethink your design.

SetAttributes[myObj, HoldFirst];
myObj[] := Module[{self = <|
      "package" -> "blabla",
      "internal parameter" -> 0 ,
      "delayed action" -> 1|>},
   myObj[self]];

myObj[self_][s_] := self[s]; Set[myObj[self_][s_], val_] ^:= self[s] = val;

obj = myObj[]; obj["package"] obj["package"] = 123 obj["package"]

Mutable data structures are available via CreateDataStructure["HashTable"] etc.

You can also use "handlers" as described at How to use Handler functions

Pavel Perikov
  • 1,345
  • 6
  • 14
3

You can use a closure:

createClosure[initState_] := Module[{state = initState, f},
  f["set", v_] := state = v;
  f["get"] := state;
  f]

x = createClosure[1]; x["get"] (* 1 ) x["set", 42]; x["get"] ( 42 *)

Victor K.
  • 5,146
  • 3
  • 21
  • 34
0

Thanks to all your suggestions! I came up with a bit different solution, but, then, realized that that it look too complex, however, it works

obj = <|"tag" -> "myassoc", "val" -> 3,

"init" :> Module[{sym, exp}, exp = Select[(StringTrim /@ (StringSplit[#, "=", 2]) & /@ ToString /@ (#[[1]]["OwnValues"] & /@ Information /@ Names["Global`*"])) , (Length[StringCases[#[[2]], "&quot;tag&quot; -> &quot;myassoc&quot;"]] > 0 && StringQ[#[[2]]] && Length[StringCases[#[[1]], "$"]] == 0) &] // First; ToExpression[exp[[1]], StandardForm, Clear];

 exp[[2]] = 
  With[{s = exp[[1]]}, 
    ToExpression[exp[[2]], InputForm, Hold] /. {This[] :&gt; s}] // 
   ReleaseHold;
 With[{s = exp[[1]], e = exp[[2]]}, 
  ToExpression[s, InputForm, Function[name, name = e, HoldAll]]];


 ],

"modify" :> With[{ref = This[]}, ToExpression[ref <> "[&quot;val&quot;]=4"];

 ]

|>;

obj["val"] 3 obj["init"]; obj["modify"]; obj["val"] 4

It fetches the defined symbol in the memory by "tag" and assigns the name of this symbol to the association.

Kirill Vasin
  • 1,235
  • 12
  • 14