IndexMut does not auto provide Index?

#1
  1. Is the following statement true: “impl IndexMut does not auto provide impl Index”

  2. I am reading: https://doc.rust-lang.org/std/ops/trait.IndexMut.html , and in particular:

impl Index<Side> for Balance {
    type Output = Weight;

    fn index<'a>(&'a self, index: Side) -> &'a Weight {
        println!("Accessing {:?}-side of balance immutably", index);
        match index {
            Side::Left => &self.left,
            Side::Right => &self.right,
        }
    }
}

impl IndexMut<Side> for Balance {
    fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Weight {
        println!("Accessing {:?}-side of balance mutably", index);
        match index {
            Side::Left => &mut self.left,
            Side::Right => &mut self.right,
        }
    }
}

Is the problem here that IndexMut operates on &'a mut self, whereas Index needs to operate on a &'a self … this, although IndexMut is “intuitively” more powerful, we can not auto convert IndexMut to Index ?

0 Likes

#2

Since index_mut requires &mut self, it is not only more powerful, but also mush more restrictive (the usual way to have it: “great power - great responsibility”). The IndexMut trait is used when we need exclusive access to the collection, and if forces the access to be exclusive; whereas Index is able to share the view into the collection with everyone else, as long as they don’t ask for & mut.

A more concrete example would be:

use std::ops::{Index, IndexMut};

fn main() {
    let mut v = vec![1, 2, 3];
    let item = v.index(1);
    let item2 = v.index(2);
    // let item3 = v.index_mut(3); // uncommenting this line yields error
    println!("{}", item);
}

Of course, this is a contrived example, in real code we’re not calling this operations explicitly, but I hope you get the point. And I hope you can understand that, if the Index trait was using IndexMut trait, the line creating item2 would yield an error too.

2 Likes