Skip to content

Can't use impl Fn to return a closure that returns another closure #62223

Open

Description

@eliaslevy

While trying to write some currying code using stable (1.35.0), writing a fn that returns impl Fn(T1) -> impl Fn(T2) -> T3 results in a compile error. E.g.

fn foo(a: i64, b: bool, c: f64) {
    println!("{:?} {:?} {:?}", a, b, c)
}

fn foo2(a: i64, b: bool) -> impl Fn(f64) -> () { move |c: f64| foo(a,b,c) }
fn foo1(a: i64) -> impl Fn(bool) -> impl Fn(f64) -> () { move |b: bool| foo2(a,b) }

fn main() {
    foo1(1)(true)(2.5);
}

results in

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/main.rs:7:37
  |
7 | fn foo1(a: i64) -> impl Fn(bool) -> impl Fn(f64) -> () { move |b: bool| foo2(a,b) }
  |                                     ^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

The expectation was that this would be allowed as the impl Fn(f64) -> () is part of the function return type of foo1.

Activity

  1. added
    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
    T-langRelevant to the language team
    on Jun 29, 2019
  2. Centril commented on Jun 29, 2019

    @Centril
    Contributor

    This is currently by design but it is a restriction we could sensibly lift imo.

  3. added
    A-closuresArea: Closures (`|…| { … }`)
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    on Jun 29, 2019
  4. dcormier commented on Jul 22, 2021

    @dcormier

    I'm being bit by this as well. It would be nice to see this changed.

  5. douglas-raillard-arm commented on Aug 9, 2022

    @douglas-raillard-arm

    I'm affected by this as well. The function is a combinator that returns a closure returning a Future, so I need the closure to return an impl Future. I worked around with a Box but it's a bit annoying to have to pay for a Box price when it's actually not really required.

    EDIT: It looks like it's possible to avoid the Box in nightly, but the pattern can become cumbersome very quickly for complicated types (e.g. impl Foo<T> with constraints on T. The constraints will need to be copy pasted, possibly multiple times over if you have "impl nesting", e.g. one layer for an Fn() and another for a impl Future returned by the Fn())
    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=d092d001154d56789a9ba77155401885

  6. added
    C-bugCategory: This is a bug.
    and removed
    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
    on Dec 8, 2023
  7. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    and removed
    C-bugCategory: This is a bug.
    on Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions