Bringing up generic associated types again


#1

I’ve seen this potential future feature mentioned since several years ago. Has there been any work toward this, or has interest faded away? I’m writing a very flexible imaging library that would benefit hugely.

Here is how a trait could look in a perfect world:

pub trait Image {
    type Index;
    type Pixel<'a>;
    fn pixel<'a> (&'a self, index: Self::Index) -> Self::Pixel<'a>;
}

// Fill returns the same value at any index.
// T is copyable, so we can just return it any time pixel() is called.
impl<T: Copy, I> Image for Fill<T, I> {
    type Index = I;
    type Pixel<'a> = T;
    fn pixel<'a> (&'a self, _: I) -> T { self.pixel }
}

// VecImage2 is a 2-dimensional image of T's backed by a Vec.
// T is possibly not copyable or even clonable, so we want to return a reference to the pixel instead of a value.
impl<T> Image for VecImage2<T> {
    type Index = Point2;
    type Pixel<'a> = &'a T;
    fn pixel<'a> (&'a self, pt: Point2) -> &'a T { ... }
}

Without the ability to parameterize the Pixel associated type with a lifetime, I can think of two ugly workarounds, both of which I’ve tried and found cumbersome.

Workaround 1:

// Parameterize the trait instead of the Pixel type.
// This gives generic functions working with images ugly and complicated signatures that sometimes don't work too well.
trait Image<'a> {
    type Index;
    type Pixel : 'a;
    fn pixel (&'a self, index: Self::Index) -> Self::Pixel;
}

impl<'a, T: 'a, I> Image<'a> for Fill<T, I> {
    type Index = I;
    type Pixel = T;
    fn pixel (&'a self, _: I) -> T { self.pixel }
}

// We can still return a reference, but at a cost of ergonomics.
impl<'a, T: 'a> Image<'a> for VecImage2<T> {
    type Index = Point2;
    type Pixel = &'a T;
    fn pixel (&'a self, pt: Point2) -> &'a T { ... }
}

Workaround 2:

// Forget about lifetimes in the trait at all.
pub trait Image {
    type Index;
    type Pixel;
    fn pixel (&self, index: Self::Index) -> Self::Pixel;
}

// Implement Image for a reference to VecImage2 instead of the struct itself.
// Now we can't make a blanket impl of Image for references to other Image types and &self is a reference to a reference.
impl<'a, T> Image for &'a VecImage2<T> {
    type Index = Point2;
    type Pixel = &'a T;
    fn pixel (&self, pt: Point2) -> &'a T { ... }
}

#2

Did you see the RFC? It’s now proposed to merge, but still needs more reviewers to sign off.
https://github.com/rust-lang/rfcs/pull/1598