Mutable iteration inside of trait

I have a trait that includes this:

trait MyTrait {
   type X<A>: IntoIterator<Item = A>;
}

Here X<A> tends to be something like (Vec<Vec<A>>,Vec<A>).

I'd like to add a method to this trait iterates over an input of type X<A> and replaces the items it holds with something else, yielding an output of type X<B>. But IntoIterator<Item = T> does not grant something like iter_mut() (only into_iter()); what is the right syntax here?

This makes me think of transforming a Vec<A> into Vec<B> with .into_iter().map(|a| a.into_b()).collect(). If I remember correctly, the standard library makes use of specialization to optimize some cases where the original Vec's allocation can be reused (even though the type has changed). Making your own method could let implementors of MyTrait optimize the X<A> -> X<B> conversion without specialization.

x.iter_mut() is generally (&mut x).into_iter(), so those bounds tend to end up as something like for<'a> &'a mut Foo: IntoIterator<Item = &'a mut Bar>.

3 Likes

I would be interested in hearing more about this! Yes X<A> tends to be something like Vec<Vec<A>>, to be turned into Vec<Vec<B>>.

Not sure I follow - I can't do

type X<T>: IntoIterator<Item = &'a mut T>;

or do you mean I put this in the where clause of the method?

Iterating over &mut T will not let you change the element types. If you need to convert X<A> into X<B> you could use X<T>: IntoIterator<Item = T> + FromIterator<T>.

pub trait MyTrait {
   type X<T>: IntoIterator<Item = T> + FromIterator<T>;
   
   fn foo<A, B>(x: Self::X<A>, f: impl Fn(A) -> B) -> Self::X<B> {
       FromIterator::from_iter(x.into_iter().map(f))
   }
}
2 Likes

Thanks for pointing this out!

But implementing FromIterator<T> also sounds a bit problematic if the exact dimensions of the original X<A> aren't obvious?

Different idea:
Implement an entrywise mapping trait, using the original dimensions.

replaces the items it holds with something else

If the new items to be inserted into X<B> are first constructed from X<A> and put inside of a flat Vec (rather than immediately using an entrywise map f as you sketched), I guess the entrywise mapping could iterate over that?