Assigning values to association in DownValues

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?

• 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... – Albert Retey Feb 7 '17 at 8:37
• @AlbertRetey Very interesting work-around! Why don't you post that as an answer? – Mr.Wizard Feb 7 '17 at 9:09
• @Mr.Wizard: thanks, just did that... – Albert Retey Feb 7 '17 at 9:30
• 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... – Albert Retey Feb 7 '17 at 10:57
• @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... – Albert Retey Feb 7 '17 at 22:35

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|>

• 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. – William Riddle Feb 7 '17 at 4:55
• @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. – Mr.Wizard Feb 7 '17 at 4:59

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