Understanding difference in mut / normal lifetimes

I would like to understand why apply_shorter compiles and why apply_implicit_mut does not.

My issue i am coming from is that I would like to use function with explicit lifetimes, like apply_mut inside trait with implicit liftime (like Iterator.next(&mut self)) In this case using apply works, but apply_mut not.

pub struct MyRefMap<'a, V, F> {
    myref: &'a V,
    fun: F,
}

impl<'a, 's, V, F, Out> MyRefMap<'a, V, F>
where
    F: Fn(&V) -> Out,
    'a : 's,
{
    pub fn apply<'b>(&'b self) -> Out where 'b : 'a {
        (self.fun)(self.myref)
    }

    pub fn apply_mut<'b>(&'b mut self) -> Out where 'b : 'a {
        (self.fun)(self.myref)
    }

	// this compiles fine / why? 
	pub fn apply_shorter(&'s mut self) -> Out {
		self.apply()
	}

	// this also compiles / ... 
	pub fn apply_anon(&'_ mut self) -> Out {
		self.apply()
	}

	// this also compiles (same as previous)
	pub fn apply_implicit(&mut self) -> Out {
		self.apply()
	}
    
	// this one that calls apply_mut() does not compile
	pub fn apply_implicit_mut(&mut self) -> Out {
		self.apply_mut()
	}
}

I believe this is a variance issue. &mut T is invariant over T, so the borrow checker is not allowed to choose a smaller lifetime for 'a. In the non-mut apply method the borrow checker is allowed to pick a shorter lifetime for 'a than the "real" lifetime of the reference which is why that version works.

If we alter the code so there's no lifetime in MyRefMap we can see that the method signatures compile as written

Playground

pub struct MyRefMap<V, F> {
    myref: V,
    fun: F,
}

impl<'a, 's, V, F, Out> MyRefMap<V, F>
where
    F: Fn(&V) -> Out,
    'a: 's,
{
    pub fn apply<'b>(&'b self) -> Out
    where
        'b: 'a,
    {
        (self.fun)(&self.myref)
    }

    pub fn apply_mut<'b>(&'b mut self) -> Out
    where
        'b: 'a,
    {
        (self.fun)(&self.myref)
    }

    pub fn apply_shorter(&'s mut self) -> Out {
        self.apply()
    }

    pub fn apply_anon(&'_ mut self) -> Out {
        self.apply()
    }

    pub fn apply_implicit(&mut self) -> Out {
        self.apply()
    }

    pub fn apply_implicit_mut(&mut self) -> Out {
        self.apply_mut()
    }
}
3 Likes

I added some notes to your original code.

3 Likes

I learned a bunch in those detailed comments you provided. Thank you.

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.