Bringing up generic associated types again

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 { ... }
}

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

2 Likes