Way to get O(1) access/set

What you describe seems to be similar to Clojure’s “transient” maps: immutable maps can be transiently mutable while they are built, and then turned into immutable ones in constant time.

I implemented something similar for the Crystal language: https://github.com/lucaong/immutable

Transient maps are NOT standard hash-maps though: hash-maps would be slow to turn into an immutable map, as you would have to traverse all entries, essentially defeating the purpose. They are still implemented as bit-array map tries, but they change the tree in a mutable way, so they are faster than immutable maps, mostly because they do not stress the garbage collector as much when many values are inserted in bulk, but they are not O(1).

While transient collections would be nice, I honestly dispute the utility of “true O(1)” collections:

  1. ETS is a good solution for most use-cases, as @jola noted. In the limited cases when even more fine-tuned performance is needed, I personally doubt that Elixir is the right choice.

  2. Immutability has profound beneficial implications for the language, and generic mutable data structures would invalidate most of them

  3. I honestly don’t know the actual implementation of large maps on the Erlang VM, but bit-array tries like in Clojure have usually a fan-out of 32, so access and update is O(log 32). That’s practically O(1), as in practical cases the number of steps is bounded by a small constant (with 1 billion elements you need no more than 7 steps, and at that point memory is a bigger problem than CPU).

  4. O(1) hash maps would have amortized O(1) updates, but they would still need re-hashing, so they have different trade-offs and aren’t unequivocally better

That said, I would still welcome attempts to improve that and I like the enthusiasm: it’s always exciting to discover new approaches, and occasionally some breakthrough data structures :slightly_smiling_face: I just don’t think this is an “essential” need for Elixir/Erlang.

5 Likes