Return closure over generic function parameter

This doesn't work:

trait FooTrait<F> {
    fn foo() -> F;
}

impl<A, R, F: Fn(A) -> R> FooTrait<F> for [A]
{
    fn foo() -> F
    {
        |x: A| x.into();
    }
}

That's because I cannot use the generic type parameter F as the return value of the function.

This works:

trait FooTrait<A, R> {
    fn foo() -> impl Fn(A) -> R;
}

impl<A, R> FooTrait<A, R> for [A]
{
    fn foo() -> impl Fn(A) -> R
    {
        |x: A| x.into();
    }
}

Although technically speaking impl XXX should desugar to <G: XXX> where G is some generic type parameter.

How do I get this working?

No. This is only true for things that are arguments to the function. When impl Trait is used as the return value, it is an existential type and not a generic parameter.

The difference is that generic parameters are chosen by the caller, whereas existential types are chosen by the implementer.

You would want something like this:

trait FooTrait {
    type F: Fn(A) -> R;
    fn foo() -> Self::F;
}

Unfortunately you can't currently implement this trait without letting F = Box<dyn Fn(A) -> R> because the existential associated type feature is still experimental.

2 Likes

Well, the return type can also be chosen by the caller by specifying the generic parameter.

The choice of return type might depend on the choices of generic parameters, but exactly how they depend on them is up to the implementer. The caller cannot say F = ThisClosureOverHere like they can with generic parameters.

1 Like

Your mention of existential associated type pointed me to some online material and I eventually solved it with this:

trait FooTrait {
    type Output;
    fn foo() -> Self::Output;
}

impl<A, R> FooTrait<A, R> for [A]
{
    type Output = Box<dyn Fn(A) -> R>;

    fn foo() -> Self::Output
    {
        Box::new(|x: A| x.into())
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.