This question popped up in my mind as I was getting ready to write an index operator for something where I can't return a reference, and now it seems that I can't do so cleanly. (I just noticed that bit-vec used the workaround of returning pointers to private static variables which is hardly ideal.)
I read/skimmed through the following:
the reddit thread on the same question, and none of the comments seem to have answered my question satisfactorily;
the bug and the corresponding the RFC on splitting Index into multiple traits;
and I don't understand the rationale for making the output always a reference. For completeness, here's the Index trait:
pub trait Index<Idx> where Idx: ?Sized {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
(Also confusing is the fact that Idx can be unsized -- if so, how do you pass it in?)
As stated in one of the reddit comments, the trait could have been
Such a trait works. It doesn't really have the semantics we want for the builtin Index trait, though. a[i] is translated to roughly *a.index(i), and that doesn't work unless indexing returns a reference.
Could you possibly elaborate on the desired semantics? Is the automatic dereferencing just for ergonomics in the case that we would want to return a reference (which is the common case for containers of non-Copy types)? Or is there a more fundamental limitation that I missed?
The idea is that array indexing should work the same way it does in C/C++: let x = a[i];, let x = &a[i];, let x = &mut a[i];, and a[i].x = 10; should have the obvious meanings.
impl Index<usize> for Vec<u8> {
type Output<'x> = &'x u8; // Not real syntax, doesn't work
fn index for<'a>(&'a self, index: usize) -> Self::Output<'a> {
// blah
}
}
But this is inexpressible in Rust today, and then precludes being able to return values again! Actually, I don't think it will ever be possible to be generic over returns value, borrows self shared, and borrows self mutably. Generic code needs to know which of these will happen in order to correctly perform borrow-checking. If the trait doesn't expose these, it simply can't.