Why doesn't this work, how do I desugar?

enum Vector<'a, T: 'a> {
    Borrowed(&'a mut [T]),
    Owned(Vec<T>),
}

impl<'a, T> Vector<'a, T> {
    fn iter(&self) -> impl Iterator<Item = &T> {
        match self {
            Self::Borrowed(value) => value.iter(),
            Self::Owned(value) => value.iter(),
        }
    }

    fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        match self {
            Self::Borrowed(value) => value.iter_mut(),
            Self::Owned(value) => value.iter_mut(),
        }
    }
}

fn main() {
    // ok
    test_simple_vector::run();
    // error
    test_complex_vector::run();
}

mod test_simple_vector {
    use super::*;
    
    type Element = u32;

    trait Iterable {
        fn iter(&self) -> impl Iterator<Item = &Element>;
        fn iter_mut(&mut self) -> impl Iterator<Item = &mut Element>;
    }

    impl<'a> Iterable for Vector<'a, Element> {
        fn iter(&self) -> impl Iterator<Item = &Element> {
            self.iter()
        }

        fn iter_mut(&mut self) -> impl Iterator<Item = &mut Element> {
            self.iter_mut()
        }
    }

    fn test_iter<I: Iterable>(i: &I) {
        println!("{:?}", i.iter().collect::<Vec<&Element>>());
    }
    
    fn test_iter_mut<I: Iterable>(i: &mut I) {
        for (index, x) in i.iter_mut().enumerate() {
            *x = index as Element + 10;
        }
        println!("{:?}", i.iter().collect::<Vec<&Element>>());
    }

    pub(super) fn run() {
        let mut v = Vector::Owned(vec![2]);
        test_iter(&v);
        test_iter_mut(&mut v);

        let borrowed_source = &mut [2];
        let mut v = Vector::Borrowed(borrowed_source);
        test_iter(&v);
        test_iter_mut(&mut v); 
    }
}

mod test_complex_vector {
    use super::*;

    #[derive(Debug)]
    struct Element<'e> {
        data: &'e str,
    }

    trait Iterable {
        fn iter(&self) -> impl Iterator<Item = &Element>;
        fn iter_mut(&mut self) -> impl Iterator<Item = &mut Element>;
    }

    impl<'a> Iterable for Vector<'a, Element<'a>> {
        fn iter(&self) -> impl Iterator<Item = &Element> {
            self.iter()
        }

        fn iter_mut(&mut self) -> impl Iterator<Item = &mut Element> {
            self.iter_mut()
        }
    }

    fn test_iter<I: Iterable>(i: &I) {
        println!("{:?}", i.iter().collect::<Vec<&Element>>());
    }

    fn test_iter_mut<I: Iterable>(i: &mut I) {
        for e in i.iter_mut() {
            *e = Element{ data: "dummy" };
        }
        println!("{:?}", i.iter().collect::<Vec<&Element>>());
    }

    pub(super) fn run() {
        let owned_source = vec![Element{ data: "hello" }, Element{ data: "world" }];
        let mut v = Vector::Owned(owned_source);
        test_iter(&v);
        test_iter_mut(&mut v);

        let borrowed_source = &mut [Element{ data: "hello" }, Element{ data: "world" }];
        let mut v = Vector::Borrowed(borrowed_source);
        test_iter(&v);
        test_iter_mut(&mut v); 
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/main.rs:87:13
   |
85 |     impl<'a> Iterable for Vector<'a, Element<'a>> {
   |          -- lifetime `'a` defined here
86 |         fn iter(&self) -> impl Iterator<Item = &Element> {
   |                 - let's call the lifetime of this reference `'1`
87 |             self.iter()
   |             ^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: lifetime may not live long enough
  --> src/main.rs:91:13
   |
85 |     impl<'a> Iterable for Vector<'a, Element<'a>> {
   |          -- lifetime `'a` defined here
...
90 |         fn iter_mut(&mut self) -> impl Iterator<Item = &mut Element> {
   |                     - let's call the lifetime of this reference `'1`
91 |             self.iter_mut()
   |             ^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: could not compile `playground` (bin "playground") due to 2 previous errors

If I manually add the lifetime specification for the RPIT, I am able to compile the trait, but I cannot pass the borrow checker.

Playground

This has nothing to do with RPITIT, but there's surely a problem with Vector<'a, Element<'a>>. If you substitute in the lifetime and type parameters, this becomes:

enum Vector<'a> {
    Borrowed(&'a mut [Element<'a>]),
    Owned(Vec<Element<'a>>),
}

of which the &'a mut [Element<'a>] part is a common anti-pattern, it essentially means a type that's borrowed for its whole lifetime, due to the invariance of mutable references.

You are also leaving off the lifetime parameter of Element (in the return type), which is bad practice, because it will be inferred to something that you don't want.

If you add a different lifetime parameter for the reference and the referent, then you can make it work, except that the mutable version still borrows the iterator forever, so you can't make it iterate mutably and immutably.

What you want is simply not possible, it's not an artefact of RPITIT.

1 Like

Thanks. This looks great, but it will cause iter() to fail to borrow because it is already borrowed as mutable. How can we call iter/iter_mut multiple times inside test_iter_mut()? Furthermore, test_iter_mut may have a sub-function call.

I do want something similar because I can't guarantee that the data is owned or borrowed, it's up to the user to decide.

Here's a version that compiles:

I made the changes mechanically for the most part and don't have time to dive into an explanation right now, but feel free to ask questions.

1 Like

Thank you very much.

This looks pretty good. I did the same thing before, and it seems like I did it the wrong way around:

    trait Iterable<'i> {
        fn iter<'s: 'i>(&'s self) -> impl Iterator<Item = &'s Element<'i>>;
        fn iter_mut<'s: 'i>(&'s mut self) -> impl Iterator<Item = &'s mut Element<'i>>;
    }

I can simply understand your code. Here, 's represents the lifetime of the self reference. The 's in Iterator Item means that the lifetime of the reference to the Element should be consistent with the lifetime of the self reference, and it is necessary to explain that the lifetime of the Element itself should exist beyond the lifetime of the self reference. This is why where exists. I don't know if I understand it correctly.

&'s Element<'i> is only valid when 'i: 's. If you then add 's: 'i, it forces 's and 'i to be the same.[1] So then you have an &'x Element<'x> which is never what you want. (Especially you never want &'x mut Element<'x>, as @paramagnetic said.)

Usually, the presence of &'s Element<'i> in the signature of a function would automatically impose an implied 'i: 's bound, but for whatever reason, this is not the case for the playground (something about RPITs probably). I added the bound mechanically based on the compiler errors.


  1. If S is a subset of I and I is a subset of S, then I == S ↩︎

1 Like

OK, I believe I understand the mystery. Then, I hope that the compiler can automatically judge 'i: 's in the future, because these details may be confusing to beginners, but in any case, this makes me have a deeper understanding of lifetime rules.

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.