# Making an Association-like interface for HashTable

SystemUtilitiesHashTable is conceptually a lot like an Association but it has the pretty phenomenal (for Mathematica) property that it's properly mutable. What I mean is that if we have a hash-table and bind it to a variable, assign it to a new variable, and mutate it there, we get the changes showing up on our original hash-table:

ht = SystemUtilitiesHashTable[]

SystemUtilitiesHashTable["<" 0 ">"]

b = ht;
SystemUtilitiesHashTableAdd[ht, "key", val];
ht

SystemUtilitiesHashTable["<" 1 ">"]


By contrast Association copies itself on assignment so this doesn't work:

ht = <||>;
b = ht;
b["key"] = val;
ht

<||>


For this an other efficiency-related reasons I'd like to use HashTable a lot more than I currently do.

One stumbling block is that the interface is annoying to use, to say the least.

Can we make this work a lot more like Association?

• The real problem seems to be, that this "is conceptually a lot like an Association" is just not true, because for an assoc immutability is probably the defining property. The API for Association is rather large, because it is integrated well with the language (so supports things like Map, Join, etc.). All that is only possible because it is immutable. For hash table being mutable, the only option you have is to may be add some interface to standard create, put, get, contains operations. Anything else, mixing it with immutable expressions, will probably just be a lot of pain at the end. – Leonid Shifrin Oct 19 '18 at 21:01
• @LeonidShifrin I think there is a use case, though, for a mutable HashTable with reasonable integration into the language. It doesn't have to be Association quality, but really just decent is good enough. Mutability is a useful property if you know what you're doing and so good enough is still very useful. – b3m2a1 Oct 19 '18 at 21:08
• The problem with mutability is that the language is not optimized for it. This means both the lack of efficiency and the lack of wide support through the language. Mixing mutable and immutable programming styles is hard and error-prone, and requires non-trivial amount of experience with the language. But in any case, making an interface for a mutable structure mimic that of an assoc, will probably not serve well most of the users. For example, in your answer you apply the "Map" function and then see a change in the original one - and IMO this is just wrong, Map should not have side effects. – Leonid Shifrin Oct 20 '18 at 15:01
• @LeonidShifrin For me, lack of mutability in the language is my least favorite part of Mathematica. Both in my own work and what I've seen across the site, people are often re-inventing OOP in limited, fragile fashion because there's no mutability, which is even less efficient. Also, while lack of efficiency is an issue, I think it just means that one has to be more clever in programming constructs. Push things that need efficiency into functions that handle the data well and whatnot. OTOH, I agree that Map the function shouldn't mutate a structure, but "Map" the method can. – b3m2a1 Oct 20 '18 at 15:43

Here's the sample package I've been working on. It simply defines the standard Association functions to work with HashTable in some reasonably efficient way.

You can get it off GitHub:

Get["https://github.com/b3m2a1/mathematica-tools/raw/master/HashTableInterface.m"]


Making a HashTable uses Association as an interface layer, so anything Association can be initialed from, HashTable can be initialized from too. Here's some sample usage:

ht = HashTable@{1 -> 2, 3 -> 4}
(*Out:*)
HashTableInterfaceHashTable[SystemUtilitiesHashTable[1, {{1, 2}, {3, 4}}]]

Keys@ht
(*Out:*)
{3, 1}

Normal@ht
(*Out:*)
<|3 -> 4, 1 -> 2|>

AssociationMap[Reverse, ht] // Normal
(*Out:*)
<|4 -> 3, 2 -> 1|>

ht@"Map"[# + 1 &]
ht // Normal
(*Out:*)
<|3 -> 5, 1 -> 3|>


I added some formatting and things as well.

The real power of this approach is seen in that last line. I added a "Map" method to the HashTable which allows the object itself to be mutated via Map` instead of creating a new object.

That opens the doors for OOP and other things.