Strange lifetime problem replacing FnMut with trait


#1

I have a function that has the following signature:

pub fn find_if<I, P>(mut f : I, l : &I, mut p : P) -> I
where I : Iterator + Readable, P : FnMut(&I::value_type) -> bool

I wanted to replace the function trait like this:

pub trait UnaryPredicate<Domain> : FnMut(Domain) -> bool {}
impl<T, D> UnaryPredicate<D> for T where T : FnMut(D) -> bool {}

and the original signature now becomes:

pub fn find_if<I, P>(mut f : I, l : &I, mut p : P) -> I
where I : Iterator + Readable, P : UnaryPredicate<&I::value_type>

The original version compiled without problems, but the new version gives me the following error:

error: : missing lifetime specifier

If I add a lifetime specifier, it still does not work, so there is something else wrong as well.

Why does it not need a lifetime specifier when using FnMut function trait directly, but it needs one when using UnaryPredicate?


#2

I am not too well versed in the specifics, but I believe this has to do with the fact that FnMut<&I::value_type> uses syntactic sugar to elide the lifetime specifier, and that sugar involves higher rank trait bounds. Those bounds are no longer sugared when you have FnMut<SomeGeneric>. These three signatures compile for me but I’m not sure which is appropriate for your use case. The third uses HRTB explicitly.

pub trait Readable {
  type value_type;
}

pub fn find_if_a<I, P>(mut f : I, l : &I, mut p : P) -> I
where I : Iterator + Readable, P : FnMut(&I::value_type) -> bool
{ unimplemented!() }

pub trait UnaryPredicate<Domain> : FnMut(Domain) -> bool {}
impl<T, D> UnaryPredicate<D> for T where T : FnMut(D) -> bool {}

pub fn find_if_b<'a, I, P>(mut f : I, l : &'a I, mut p : P) -> I
where I : Iterator + Readable, P : UnaryPredicate<&'a I::value_type>
{ unimplemented!() }

pub fn find_if_c<I, P>(mut f : I, l : &I, mut p : P) -> I
where I : Iterator + Readable, for <'a> P : UnaryPredicate<&'a I::value_type>
{ unimplemented!() }

fn main() {
}

#3

Fn has implicit lifetime polymorphism

You can use this explicit

for<'a> P : UnaryPredicate<&'a I::value_type>

#4

I have used

pub fn find_if<I, P>(mut f : I, l : &I, mut p : P) -> I
where I : Iterator + Readable, P : for<'a> UnaryPredicate<&'a I::value_type>

However I now get a different error:

src/lib.rs:478:36: 478:38 error: the type of this value must be known in this context
src/lib.rs:478         for_each(find_if(f, l, |v| *v==j), l, |v| s += (*v).clone());
                                                  ^~

Which I didn’t get using FnMut directly. Is FnMut doing some other magic?