# Why Fn trait doesn't constrain generic param

Just trying to understand why does following code fail with `the type parameter 'R' is not constrained by the impl trait, self type, or predicates`, looks pretty constrained to me.

``````trait Tr {}

struct W<F>(F);

// Why it doesn't work?
impl<F,I,R> Tr for W<F>
where F: FnOnce(I) -> R
{}
``````

To work with `Fn`s in my generic code I have to wrap them all, which is a major inconvenience:

``````// Workaround
struct Fun<F,I,R>(F, PhantomData<fn(I)->R>);

impl<F,I,R> Tr for W<Fun<F,I,R>>
where F: FnOnce(I) -> R
{}
``````

In theory, one type can implement both `FnOnce(I) -> R1` and `FnOnce(I) -> R2` for different types `R1` and `R2`, which would make your first implementation ambiguous.

That's what I don't understand, how single type can implement both `FnOnce(I) -> R1` and `FnOnce(I) -> R2` ? It can't, `FnOnce` is a closure or `fn` if nothing is captured and both arguments and return values are set for it.

I don’t think that is possible, actually, since the following is not ambiguous:

``````struct Fun<F, R>(F)
where
F: FnOnce() -> R;
``````

playground

However, it is possible for a single type to implement `FnOnce` with different argument types, e.g. with lifetimes:

``````pub fn f() -> impl for<'a> FnOnce(&'a str) -> &'a str {
|x| x
}
``````

playground.
Here return type of `f` implements `FnOnce(I)->R` for a potentially infinite number of `I`, `R` pairs.

2 Likes

`R` is not constrained because `I` is not constrained. If `I` was constrained, `R` would be constrained too.

That is, you can't implement both

• `FnOnce(I) -> R1`
• `FnOnce(I) -> R2`

But you can certainly implement both

• `FnOnce(I1) -> R1`
• `FnOnce(I2) -> R2`

Which I think is what @itim was getting at.

1. Given the current unstable `Fn` traits (which might be hard to evolve past) ↩︎

6 Likes

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.