There's a thread (now closed) about generalizing Index and IndexMut to return "view" types that aren't references. There's also a prior RFC which was declined for accidentally proposing a solution that breaks backwards compatibility.
Here, I'd like to discuss a potential non-breaking solution: adding new indexing trait which supersedes the old ones, while providing covering implementations for types that implement the old types. More concretely:
trait CoolIndex<'a, Idx: ?Sized> {
type Output: ?Sized;
fn cool_index(&'a self, index: Idx) -> Self::Output;
}
impl<'a, T> CoolIndex<'a, usize> for TypeWithView<T>
where T: 'a
{
type Output = View<'a, T>;
fn cool_index(&'a self, index: usize) -> View<'a, T> {
magic!()
}
}
This is essentially copied from @CAD97's solution from the RFC, which is similar to @japaric's attempt #3 from 2014. Heres's a playground with a more complete definition plus examples.
For me, I have the following unanswered questions:
-
If we're parametrizing the trait with the lifetime
'a, are there any issues lettingcool_indextake ownership ofselfand instead implementCoolIndex<'a, _>for&'a Whatever?Update: I tried out something like this in the playground. Benefit: the one trait can be implemented for both
&'a Tand&'a mut T. Problem: we lose syntactic disambiguation via&_[_]vs&mut _[_](and people would probably be surprised if something with&in the calling syntax could somehow take ownership of the referent). -
Could someone give a more concrete example of how lifetime contravaiance in the returned "view" type causes problems? To me it looks like
CoolIndexhas a straightforward translation toIndex, which would have the same lifetime issues if any.