1
$\begingroup$

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.

$\endgroup$
2
  • $\begingroup$ A one little addition: I can get the expression by using %, but I can't modify it. Even with classic trick with associations % = Append[%, "internal parameter"->1] $\endgroup$ Commented Dec 30, 2021 at 9:23
  • 2
    $\begingroup$ Not quite the same, but I did write a resource function that allows you to create associations that reference themselves: AssociationTemplate. $\endgroup$ Commented Dec 30, 2021 at 10:54

3 Answers 3

3
$\begingroup$

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

$\endgroup$
3
$\begingroup$

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 *)
$\endgroup$
0
$\begingroup$

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]], "\"tag\" -> \"myassoc\""]] > 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[] :> s}] // 
       ReleaseHold;
     With[{s = exp[[1]], e = exp[[2]]}, 
      ToExpression[s, InputForm, Function[name, name = e, HoldAll]]];
     
     
     ],
   
   "modify" :> With[{ref = This[]},
     ToExpression[ref <> "[\"val\"]=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.

$\endgroup$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.