4
$\begingroup$

Compare the following code:

Clear[t];
t = <||>;
t[2] = 1/2;
t[2]

with

Clear[t];
t[2] = <||>;
t[2][2] = 1/2;
t[2][2]

The first works and the second doesn't. And AssociateTo[t[2], 2->1/2] works. What is the difference of mechanism behind the two methods?

$\endgroup$
  • 1
    $\begingroup$ is there any good reason why you don't make t an Association in the first place also for case 2? t=<||>;t[2] = <||>;t[2][2] = 1/2 works very nicely and seems the best fit as long as you use the downvalues of t as a hash table anyway... $\endgroup$ – Albert Retey Feb 7 '17 at 8:37
  • $\begingroup$ @AlbertRetey Very interesting work-around! Why don't you post that as an answer? $\endgroup$ – Mr.Wizard Feb 7 '17 at 9:09
  • $\begingroup$ @Mr.Wizard: thanks, just did that... $\endgroup$ – Albert Retey Feb 7 '17 at 9:30
  • 1
    $\begingroup$ while there is no default value for Association there is Lookup which lets you extract by key and give a default value when the key is not present. That will of course need adaption to the existing code, but it should provide the functionality you are searching for... $\endgroup$ – Albert Retey Feb 7 '17 at 10:57
  • 1
    $\begingroup$ @Mr.Wizard: sorry with "it works" I just meant that Lookup does what is documented. Of course there are use cases like the ones you mention where it isn't doing what is needed. I think it is still worth mentioning that Lookup exists and suggest to use it where appropriate, even if it doesn't cover every use case (and taste). That doesn't mean I wouldn't appreciate if WRI would provide an Association which supports defaults if that is possible... $\endgroup$ – Albert Retey Feb 7 '17 at 22:35
7
$\begingroup$

This is nothing unique to Association; the same issue affects simple lists:

a[1] = {1, 2, 3};

a[1][[2]] = 7;

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

For full examination of this problem see: How to Set parts of indexed lists?

As you can see from the answers to that question there is no universally satisfying and clean solution.

You wrote: "And AssociateTo[t[2], 2->1/2] works." On my system (v10.1.0) it does not:

t[2] = <||>;
AssociateTo[t[2], 2 -> 1/2]

AssociateTo::rvalue: t[2] is not a variable with a value, so its value cannot be changed. >>

If this has been amended in more recent versions then I'd say it is the canonical solution to this problem. For older versions there is this:

t[2] = <|t[2], 2 -> 1/2|>;

t[2]
<|2 -> 1/2|>
$\endgroup$
  • 1
    $\begingroup$ Thanks! I am using version 11 and that AssociationTo worked. Perhaps you can try this on their free cloud platform. It is surprising that they changed design of part of the core language. $\endgroup$ – William Riddle Feb 7 '17 at 4:55
  • $\begingroup$ @WilliamRiddle I do not find that surprising as is not an incompatible change; rather it is an extension or bug-fix, depending on one's perspective. $\endgroup$ – Mr.Wizard Feb 7 '17 at 4:59
4
$\begingroup$

This does not exactly answer your question, but it indicates how you can avoid the problem you have detected in almost all use cases: using downvalues as a hashtable is possible and often recommended, but since version 10 we have Associations which were introduced exactly for that purpose, whereas the use of downvalues as a hashtable looks more like an accidential benefit of pattern matching optimizations. The problem you have indicated is actually one of the most convincing use cases that justify the addition of a fundamental new datatype to Mathematica after more than 20 years. This should work with any recent version:

ClearAll[t]
t=<||>
t[2]=<||>
t[2][2]=1/2
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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