Summary
The IndexMut
trait isn’t suitable for python-like assignment of dictionary elements; this can be changed by adding an IndexAssign
trait defined something like this:
pub trait IndexAssign<Idx> {
type Value;
fn index_assign(&mut self, idx: Idx, value: Self::Value);
}
impl<C, Idx> IndexAssign<Idx> for C
where
C: IndexMut<Idx>,
C::Output: Sized,
{
type Value = C::Output;
fn index_assign(&mut self, idx: Idx, value: Self::Value) {
*self.index_mut(idx) = value;
}
}
Detailed Description
In the exact case of container[key] = value
, the code would desugar to container.index_assign(key, value)
, instead of *container.index_mut(key) = value
.
Backwards Compatibility
This behavior is backwards compatible with existing code that only implements IndexMut
, because internally the default implementation for cases where assignment is possible is the same behavior as before. The following related statements will be unaffected:
container[key] += value
container[key] -= value
container[key] *= value
container[key] /= value
container[key] |= value
container[key] &= value
container[key] ^= value
container[key] <<= value
container[key] >>= value
Additionally, the blanket impl for IndexAssign
prevents existing code from being affected; in the case of objects like Vec<T>
, IndexAssign
will behave the same; since as it stands right now assignment of unsized types isn’t really possible, the restriction on C::Output: Sized
isn’t restrictive.
Advantages
- Additional level of control for users that opt in
- APIs to containers can be much more flexible
- Can currently be implemented without breaking existing code
Drawbacks
- Additional language complexity
- Work to implement into compiler
Alternatives
- None for the desired effect
Edits: Altered suggested implementation to make trait more flexible.