core::ops::IndexMut for alloc::collections::HashMap

Why doesn’t HashMap’s implement IndexMut? I always have to write a wrapper around HashMap when I need to change values in it or to use HashMap::get_mut. This isn’t cool, so why?

I think that the language designers want to someday support inserting as map[new_key] = new_value. The current Index… traits can’t do this, and they don’t want to accidentally paint themselves into a corner before they figure out a better way.

3 Likes

Just in case someone misses these threads:

And maybe much more threads...

4 Likes

@2e71828, @vague. Thanks for your replies. I still don't understand why not just add index_mut without inserting to HashMap, but ok.

  • Many people will still expect map["foo"] = "bar" to insert into the map, but it doesn't, so they'll find it confusing
  • It removes the ability to implement it in future in the expected way.
1 Like
  1. But there's traditional HashMap::insert :upside_down_face:
  2. Why does it?

FYI, even for indexmap::IndexMap, a data structure used as HashMap and Vec, its IndexMut impls (1 and 2) say:

Access IndexMap values corresponding to a key.

Mutable indexing allows changing / updating values of key-value pairs that are already present.

You can not insert new pairs with index syntax, use .insert().

map.insert("foo", 1); // ok
map["bar"] = 1; // panics!
map[10] = 1; // panics!

But that's cool! Pushing to HashMap via different from index_mut method prevents some logical errors.

And not everyone knows that. Many people come from other languages and expect it to work, so they'll get bitten by it. "But it works for something else" is not a good reason to leave such a huge footgun.

Because if map["foo"] = "bar" is guaranteed to panic if "foo" is not in the map then suddently making this code insert a new entry with a "foo" key and "bar value is a breaking change and can't be done.

4 Likes

They could have still done it and just called it “undefined behavior”, but if C/C++ fiasco have teached us anything then we shouldn't try that: when documentation says that something is “undefined behavior” yet implementation consistently works in a certain way then people would just assume documentation is wrong and would become extremely upset when later behavior would change.

You cannot trigger UB using only safe code. This would be one of the most important guarantee the Rust provides.

2 Likes

Yes, it would be unspecified behavior in C parlance. Anyway, leaving something like this unspecified would of course be totally nuts.

1 Like

People coming from other languages may expect variables to be mutable by default or every type to be automatically copyable then. Inserting via index is just a silly thing that may cause bugs just because of a little typo.

And if they do, the compiler will inform them that this is not the case in Rust with an error. map["foo"] = "bar" would compile, but might not mean what the programmer expects it to mean.

1 Like

If there's no "bar" key, the coder will get a panic. I don't know how to inspect a HashMap at compile time, but panic is much better than wrongly working logic.

Panic is better than wrongly working logic, but if you don't expect it (and believe me, lots of newbies wouldn't expect it), it may take a long time to debug and understand what the heck happens.

Especially since it's so “obvious” that such code should add new element that lots of them wouldn't even suspect it may not work like that.

1 Like