Nifty, powerful, and simple, like so much of Erlang.
But also like so much of Erlang, I think the modern approaches (several of them) that languages take to serialization is better. It's a good first pass cut at the problem, but I prefer all of the GRPC approach to the problem, the JSON approach to the problem, and honestly just letting the chips fall where they may with most modern serialization libraries. Treat the remote system as not entirely trusted and handle the messages with a bit of skepticism generally works out for quite a bit of scaling. And you get user types back, which means you are no longer stuck on the BeamVM's quite anemic data types.
If you look at the underlying implementations of an Erlang map, you'll see why you're not getting vectors anytime soon.
1> dict:append(a, b, dict:new()).
{dict,1,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
{{[],[[a,b]],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}
It's a big pile of linked lists storing assoc lists held together by tuples, with all the component value being dynamically typed. It's nice they didn't cheat on that, but it is... not the most efficient approach to dictionaries, just the one enabled by their type system, such as it is.All kidding aside, unless I'm interviewing at an Elixir shop, I've learned that Elixir is a little too weird for interviewers who don't know Elixir very well.
With a big caveat that modifying tuples isn't great for performance unless the compiler or optimizer determine that mutating the tuple is acceptable rather than providing a mutated copy.
Even clojure's is a cheat.
This occurred somewhat recently when implementing stable topological sort. I ended up swapping List out for a Vector (Aja is library I used). I received a 100x performance improvement from it.
That's really the only time I've truly hit a List performance roadblock in 7+ years of Elixir.
Vectors are usually also homogeneous about the data they hold, because each element should occupy the same fixed amount of memory, such as i*item_size gievs you back the offset of the element i in memory.
Anyway, in Elixir you can use the Erlang's :array module
Access in O(1) instead of O(nlogn).
Both maps and vectors in Clojure are trees, albeit very shallow trees (32-way branching). The difference lies in the interfaces and the lookup methods. (Maps hash keys and use bits to know which subtree to descend, while vectors use index bits.)
all the JVM languages
all the .Net languages
Rust
Ruby
Python
etc.
irb(main):002:0> ["GFG", "GFG", "GFG", "GFG"].class
=> Array
irb(main):003:0> {1 => "CFG", 2 => "CFG"}.class
=> Hash
irb(main):006:0> {1 => "CFG", 2 => "CFG"}.keys.class
=> Array
irb(main):007:0> {1 => "CFG", 2 => "CFG"}.values
=> ["CFG", "CFG"]
irb(main):008:0> {1 => "CFG", 2 => "CFG"}.values.class
=> Arrayhttps://docs.python.org/3/library/array.html
>>> a = array('B', [1, 2, 3, 4, 5])
>>> str(a.buffer_info()[1] * a.itemsize) + " bytes at address #" + str(a.buffer_info()[0])
'5 bytes at address #4379640336'
>>> b = array('l', [1, 2, 3, 4, 5])
>>> str(b.buffer_info()[1] * b.itemsize) + " bytes at address #" + str(b.buffer_info()[0])
'40 bytes at address #4380812752'