Is there a way to overload []=?

I know about IndexMut.

I would like to overload []= instead if possible, i.e.
fn set(&mut self, index: K, value: V) { ... }

The application here is: I want to log all "changes" to a data structure. Thus, I want a set instead of IndexMut (unless there is some way to do this with IndexMut I am unaware of).

This doesn't have exist yet, although there have been proposals where it was called IndexAssign iirc.

Perhaps you'd be better off just using methods rather than Index and assignments, then you can put whatever code you want, at the cost of it being slightly less convenient to use

1 Like

IndexMut results in a mutable place expression that you can move into or take a &mut to, so there's no way to do it with that. More generally, if you can get a &mut of the field (or of any parent or ownership of any parent), it can be replaced by e.g. moves or other "primitive" operations.

If it's always full assignment you're dealing with (e.g. some opaque type with no mutating methods), maybe you could do something with Drop. Though someone on the other side could mem::replace and hold on to or leak the original. Some sort of Cell or Option wrapper is another possibility.

3 Likes

Another option along these lines would be to define a transaction object that applies changes on Drop:

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

struct MyVec<T>(Vec<T>);

impl<T> MyVec<T> {
    pub fn xact(&mut self) -> Xact<'_, T> {
        Xact {
            store: &mut self.0,
            diff: HashMap::new(),
        }
    }
}

struct Xact<'a, T> {
    store: &'a mut Vec<T>,
    diff: HashMap<usize, T>,
}

impl<T> Index<usize> for Xact<'_, T> {
    type Output = T;
    fn index(&self, i: usize) -> &T {
        self.diff.get(&i).unwrap_or(&self.store[i])
    }
}

impl<T:Clone> IndexMut<usize> for Xact<'_,T> {
    fn index_mut(&mut self, i:usize)->&mut T {
        self.diff.entry(i).or_insert_with(|| self.store[i].clone())
    }
}

impl<T> Drop for Xact<'_,T> {
    fn drop(&mut self) {
        for (k,v) in self.diff.drain() {
            self.store[k]=v;
        }
    }
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.