Lifetime of self embedded in Self, not &'a self

Below I have

impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
	fn as_poly_iterator(
		&self
	) -> Result<

which shouldn't need &'a self because the 'a already comes from MyPolynomial<'a, T>. Also, I should pass &'a[T] in PolyIterator::new in the line

let iterator = PolyIterator::new(self.coefficients.as_life_ref());

but I'm getting an error saying that it wants a &'a (dyn Mem<'a, T> + 'a) which I have no idea why.

pub trait Mem<'r, T>
{
    fn as_life_ref(&'r self) -> &'r [T];
}

pub struct PolyIterator<'a, T> {
	coefficients:   &'a [T]
}

impl<'a, T> PolyIterator<'a, T> {
    pub fn new(coefficients: &'a[T]) -> PolyIterator<'a, T> {
        todo!()
    }
}

pub struct MyPolynomial<'a, T> {
	coefficients:   Box<dyn Mem<'a, T> + 'a>,
}

pub trait AsPolyIterator<'a, T> {
	fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}

impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
	fn as_poly_iterator(
		&self
	) -> Result<
		PolyIterator<'a, T>,
		(),
	> {
		let iterator = PolyIterator::new(self.coefficients.as_life_ref());
		todo!()
	}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/lib.rs:31:54
   |
31 |         let iterator = PolyIterator::new(self.coefficients.as_life_ref());
   |                                                            ^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/lib.rs:26:3
   |
26 |         &self
   |         ^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:31:36
   |
31 |         let iterator = PolyIterator::new(self.coefficients.as_life_ref());
   |                                          ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/lib.rs:24:6
   |
24 | impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
   |      ^^
note: ...so that the types are compatible
  --> src/lib.rs:31:54
   |
31 |         let iterator = PolyIterator::new(self.coefficients.as_life_ref());
   |                                                            ^^^^^^^^^^^
   = note: expected `&'a (dyn Mem<'a, T> + 'a)`
              found `&(dyn Mem<'a, T> + 'a)`

Your Mem trait is overconstrained: it ties the lifetime of the returned reference to that of self, even though your stated goal is explicitly to avoid that situation. Try this instead:

pub trait Mem<'r, T>
{
    fn as_life_ref(&self) -> &'r [T];
}
2 Likes

do you know why I have to do

pub trait Mem<'r, T: 'r>
{
    fn as_life_ref(&self) -> &'r [T];
    fn len(&self) -> usize {
        self.as_life_ref().len()
    }
}

that is, add T: 'r, if I want to actually implement stuff on Mem? Is it because T could be a reference? Even if it is a reference, why do I need it to be T: 'r if I just want to use it for getting the len?

ok I just remembered why I had &'r on as_life_ref. Without it I cannot do:

impl<'r, T: 'r + Send> Mem<'r, T> for Vec<T> {
    fn as_life_ref(&self) -> &'r [T] {
        self.as_slice()
    }
}

If Mem<T> is implemented by something that owns a T, what good is 'r?

You will probably say "But then I can't implement Mem<'a, T> to return 'a-lifetimed references to my struct that contains &'a Ts!" And I will answer: that is the point! If you want to generalize over different ways of storing T, namely &'a T and T, you cannot write a function that returns 'a-bound references for some implementors and &self-bound references for other implementors. That's the opposite of generalization; you might as well have two Mem traits, Mem and MemRef...

... Which you actually already have, if you change the T parameter, but perhaps I misunderstand the problem.

I wanted to support 2 cases: returning a slice from a static "self-living" object like Vec<T> for when I want to send objects with Box<dyn Mem<...>> to other threads, but also support returning a slice of short-living objects which are efficiently allocated by a memory pool like TypedArena, but can't be sent to other threads.

So Box<dyn Mem<'a, T> + 'static> could accomodate the Vec, because Vec is essentially a dyn Mem<'a, T> with 'static lifetime, and Box<dyn Mem<'r, T> + 's> could accomodate the short-lived reference of lifetime s allocated by TypedArena. Maybe even Box<dyn Mem<'s, T> + 's> since the allocated object by the typed arena is the same of the slice

Yes, Mem<T> with no lifetime parameter can support either of those use cases, if I understand you correctly.

No, that's exactly what you must not do, because Mem has to also support storing a Vec and returning lifetimes that are derived from self, and you can't take a &'s dyn Mem<'s, T> unless you borrow it for its entire lifetime (essentially it's the same as a self-referential struct).

You mean something like this?

pub trait Mem<T> {
    fn as_ref(&self) -> T;
}

impl<'a, T> Mem<&'a T> for Vec<T> {
    fn as_ref(&self) -> &'a T {
        self.as_slice()
    }
}

Also tried

pub trait Mem<T> {
    fn as_ref(&self) -> T;
}

impl<T> Mem<&T> for Vec<T> {
    fn as_ref(&self) -> &T {
        self.as_slice()
    }
}

without success

EDIT: ops I mean

pub trait Mem<T> {
    fn as_ref(&self) -> T;
}

impl<'a, T> Mem<&'a [T]> for Vec<T> {
    fn as_ref(&self) -> &'a [T] {
        self.as_slice()
    }
}

I think he means like this

pub trait Mem<T>: Send
{
    fn as_life_ref(&self) -> &[T];
    fn len(&self) -> usize {
        self.as_life_ref().len()
    }
    fn is_empty(&self) -> bool { self.as_life_ref().len() == 0 }
}

playground
oops
better playground

1 Like
pub struct MyPolynomial<T> {
	coefficients:   Box<dyn Mem<T>>,
}

this makes the internals of Box<dyn Mem<T>> as being able to hold only 'static livable objects, which is the case for Vec, but what if I have a short-lived reference? I cannot store it there because Box<dyn Mem<T>> = Box<dyn Mem<T> + 'static> . Also, I cannot set T=&'a T I guess? How would it work for a short-lived reference?

It looks like that with this I cannot do this basic thing :neutral_face:

Are you trying to do something like this? If not, can you put everything you're trying to do in a single playground?

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.