Skip to content

Remove old (boxed) closures from the language #14798

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
pcwalton opened this issue Jun 10, 2014 · 5 comments · Fixed by #20578
Closed

Remove old (boxed) closures from the language #14798

pcwalton opened this issue Jun 10, 2014 · 5 comments · Fixed by #20578
Labels
A-closures Area: Closures (`|…| { … }`) A-type-system Area: Type system
Milestone

Comments

@pcwalton
Copy link
Contributor

We will want to remove (old) boxed closures from the language for 1.0, I believe. At the very least we should feature gate them.

Nominating for 1.0, P-backcompat-lang.

@pnkfelix pnkfelix changed the title Remove boxed closures from the language Remove (old) boxed closures from the language Jun 12, 2014
@emberian emberian changed the title Remove (old) boxed closures from the language Remove old (boxed) closures from the language Jun 12, 2014
@pnkfelix
Copy link
Member

Assigning P-backcompat-lang, 1.0.

@Rdbaker
Copy link

Rdbaker commented Jun 30, 2014

How would one go about this?

@huonw
Copy link
Member

huonw commented Jun 30, 2014

@Rdbaker the new closures don't quite exist yet (#14539), so the best thing for now is waiting. :)

@aturon aturon mentioned this issue Oct 16, 2014
47 tasks
@gamazeps
Copy link
Contributor

gamazeps commented Nov 3, 2014

@huonw and now ? :p

@huonw huonw added the A-closures Area: Closures (`|…| { … }`) label Nov 3, 2014
@huonw
Copy link
Member

huonw commented Nov 3, 2014

Not really ready. See #18101. In particular #17661.

bors added a commit that referenced this issue Jan 5, 2015
This PR removes boxed closures from the language, the closure type syntax (`let f: |int| -> bool = /* ... */`) has been obsoleted. Move all your uses of closures to the new unboxed closure system (i.e. `Fn*` traits).

[breaking-change] patterns

- `lef f = || {}`

This binding used to type check to a boxed closure. Now that boxed closures are gone, you need to annotate the "kind" of the unboxed closure, i.e. you need pick one of these: `|&:| {}`, `|&mut:| {}` or `|:| {}`.

In the (near) future we'll have closure "kind" inference, so the compiler will infer which `Fn*` trait to use based on how the closure is used. Once this inference machinery is in place, we'll be able to remove the kind annotation from most closures.

- `type Alias<'a> = |int|:'a -> bool`

Use a trait object: `type Alias<'a> = Box<FnMut(int) -> bool + 'a>`. Use the `Fn*` trait that makes sense for your use case.

- `fn foo(&self, f: |uint| -> bool)`

In this case you can use either a trait object or an unboxed closure:

``` rust
fn foo(&self, f: F) where F: FnMut(uint) -> bool;
// or
fn foo(&self, f: Box<FnMut(uint) -> bool>);
```

- `struct Struct<'a> { f: |uint|:'a -> bool }`

Again, you can use either a trait object or an unboxed closure:

``` rust
struct Struct<F> where F: FnMut(uint) -> bool { f: F }
// or
struct Struct<'a> { f: Box<FnMut(uint) -> bool + 'a> }
```

- Using `|x, y| f(x, y)` for closure "borrows"

This comes up in recursive functions, consider the following (contrived) example:

``` rust
fn foo(x: uint, f: |uint| -> bool) -> bool {
    //foo(x / 2, f) && f(x)  // can't use this because `f` gets moved away in the `foo` call
    foo(x / 2, |x| f(x)) && f(x)  // instead "borrow" `f` in the `foo` call
}
```

If you attempt to do the same with unboxed closures you'll hit ""error: reached the recursion limit during monomorphization" (see #19596):

``` rust
fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool {
    foo(x / 2, |x| f(x)) && f(x)
    //~^ error: reached the recursion limit during monomorphization
}
```

Instead you *should* be able to write this:

``` rust
fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool {
    foo(x / 2, &mut f) && f(x)
    //~^ error: the trait `FnMut` is not implemented for the type `&mut F`
}
```

But as you see above `&mut F` doesn't implement the `FnMut` trait. `&mut F` *should* implement the `FnMut` and the above code *should* work, but due to a bug (see #18835) it doesn't (for now).

You can work around the issue by rewriting the function to take `&mut F` instead of `F`:

``` rust
fn foo<F>(x: uint, f: &mut F) -> bool where F: FnMut(uint) -> bool {
    foo(x / 2, f) && (*f)(x)
}
```

This finally works! However writing `foo(0, &mut |x| x == 0)` is unergonomic. So you can use a private helper function to avoid this:

``` rust
// public API function
pub fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool {
    foo_(x, &mut f)
}

// private helper function
fn foo_<F>(x: uint, f: &mut F) -> bool where F: FnMut(uint) -> bool {
    foo_(x / 2, f) && (*f)(x)
}
```

Closes #14798

---

There is more cleanup to do: like renaming functions/types from `unboxed_closure` to just `closure`, removing more dead code, simplify functions which now have unused arguments, update the documentation, etc. But that can be done in another PR.

r? @nikomatsakis @aturon (You probably want to focus on the deleted/modified tests.)
cc @eddyb
bors pushed a commit to rust-lang-ci/rust that referenced this issue Aug 21, 2023
bors added a commit to rust-lang-ci/rust that referenced this issue Aug 21, 2023
add check.ignore to list cargo check diagnostics to ignore (dead_code, unused_imports, ...)

fixes rust-lang#14798
flip1995 pushed a commit to flip1995/rust that referenced this issue May 31, 2025
`if` expressions don't necessarily contain a block in the `else` part in
the presence of an `else if`. The `else` part, if present, must be
handled as a regular expression, not necessarily as a block expression.

Found while applying Clippy to triagebot and looking at the result. This
also found an issue in Clippy itself.

changelog: [`needless_return`]: look inside `else if` parts as well
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-type-system Area: Type system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants