Higher ranked trait bounds preventing a GAT over reference types

Hi there, I am making a tensor processing library and I have run into a bug that I am not able to solve.

I have a trait TensorLike that I am implementing for various structs, and it requires an HRTB so that I can make an iterator over elements of any TensorLike. However, I have now added a GAT as a return type of the shape() function to abstract over Ref<'a, Vec<usize>> and &'a Vec<usize>.
The reason for this is that I will need to build up a graph of ancestors of each TensorLike to support automatic differentiation.

The problem is that if I specify the lifetime of the return type, in one struct, as &Vec<usize> I get a "not general enough" error. But if I don't then I get a compile time error because the lifetime cannot be inferred.

Any suggestion on resolving these competing requirements?

playground link

I'm really not an expert (or particularly knowledgeable) in these advanced type mechanisms but I found it a bit odd that trait TensorLike<'a> is generic over a lifetime parameter that isn't actually used in any of its associated items, so I removed it and rewrote things to look like this:

I don't know if this achieves what you are trying to do but it compiles.

2 Likes

Rust Playground

pub trait TensorLike {
    type Elem;
    type ShapeReturn<'shape>: 'shape + Deref<Target = [usize]>
    where
        Self: 'shape;
    fn get(&self, _index: &[usize]) -> Self::Elem;

    fn shape(&self) -> Self::ShapeReturn<'_>;
}

modifications:

  • remove the lifetime parameter on TensorLike
  • use GAT on ShapeReturn
  • ShapeReturn: Deref<Target = [usize]> instead of Deref<Target = Vec<usize>>
1 Like

Thank you both! Those suggestions fixed the problem -- I hadn't realised I could put a lifetime directly on the GAT, rather than in the trait definition!

I just couldn't find that note amusing. GATs, quite literally, exist to put lifetimes on them!

Yes, they could be used for other purposes, too, but an announcement and other things related to GATs were always concentrating on the lifetimes and everything else was supposed to be just a bonus. There were even discussions about only allowing lifetimes with GATs (but eventually it was decided that other GATs are useful, too).

And now people start using them… without realising that they can be used with lifetimes.

It's like an attempt to use car without understanding you can use it to go from point A to point B or use a boat without realizing it's not supposed to be permanently anchored.

P.S. Correction: after looking on the first link I have realised that the confusion is even deeper. Because the first example where “GATs don't work” doesn't include any GATs at all… Indeed GATs do exist to precisely to solve the dilemma with associated lifetimes as they existed before GATs.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.