New issue

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

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

Already on GitHub? Sign in to your account

(expected closure, found a different closure) [E0308] #24036

Closed
richo opened this Issue Apr 4, 2015 · 6 comments

Comments

Projects
None yet
3 participants
@richo
Contributor

richo commented Apr 4, 2015

playpen

The error here is extremely unclear to me:

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let op = match &args[1][..] {
        "foo" => |c: i32| c + 1,
        "bar" => |c: i32| c + 1,
        "baz" => |c: i32| c - 1,
        "other" => |c: i32| c - 1,
        _ => return,
    };
    println!("{:?}", op(11));
}

Not sure if actually a bug in rust (That's my intuition, this looks very valid to me) or just an issue where the error message is incredibly unhelpful.

<anon>:5:14: 11:6 error: match arms have incompatible types:
 expected `[closure <anon>:6:18: 6:32]`,
    found `[closure <anon>:7:18: 7:32]`
(expected closure,
    found a different closure) [E0308]
<anon>:5     let op = match &args[1][..] {
<anon>:6         "foo" => |c: i32| c + 1,
<anon>:7         "bar" => |c: i32| c + 1,
<anon>:8         "baz" => |c: i32| c - 1,
<anon>:9         "other" => |c: i32| c - 1,
<anon>:10         _ => return,
          ...
<anon>:7:18: 7:32 note: match arm with an incompatible type
<anon>:7         "bar" => |c: i32| c + 1,
                          ^~~~~~~~~~~~~~
error: aborting due to previous error
@ebfull

This comment has been minimized.

Contributor

ebfull commented Apr 4, 2015

The error is a bit confusing if you're not familiar with closures. Check out the chapters on Closures and Static and Dynamic Dispatch in the book to understand the semantics and performance tradeoffs.

Currently in Rust, no two closures, even if identical, have the same type. Closures are essentially anonymous structs (containing the environment they close over) expanded at compile time, and made to impl the Fn* family of traits.

In your code, producing a bare closure from a match arm that could produce other closures is not possible. You must use trait objects. The easiest approach would probably be to just box each closure, and coerce it into a trait object with a type annotation.

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    let op: Box<Fn(i32) -> i32> = match &args[1][..] {
        "foo" => Box::new(|c: i32| c + 1),
        "bar" => Box::new(|c: i32| c + 1),
        "baz" => Box::new(|c: i32| c - 1),
        "other" => Box::new(|c: i32| c - 1),
        _ => return,
    };
    println!("{:?}", op(11));
}

There may be other ways to accomplish what you want. And if you aren't closing over your environment, just use function pointers.

use std::env;

fn first_thing(c: i32) -> i32 {
    c + 1
}

fn second_thing(c: i32) -> i32 {
    c - 1
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let op: fn(i32) -> i32 = match &args[1][..] {
        "foo" => first_thing,
        "bar" => first_thing,
        "baz" => second_thing,
        "other" => second_thing,
        _ => return,
    };
    println!("{:?}", op(11));
}

Or if your situation ultimately allows for it, use generics in some way.

@richo

This comment has been minimized.

Contributor

richo commented Apr 4, 2015

Sorry, I forgot to mention that this is a regression from about a week ago when https://github.com/richo/karma-rs/blob/master/src/main.rs#L49-L55 built
On Friday, April 3, 2015, ebfull notifications@github.com wrote:

The error is a bit confusing if you're not familiar with closures. Check
out the chapters on Closures http://doc.rust-lang.org/book/closures.html
and Static and Dynamic Dispatch
http://doc.rust-lang.org/book/static-and-dynamic-dispatch.html in the
book to understand the semantics and performance tradeoffs.

Currently in Rust, no two closures, even if identical, have the same type.
Closures are essentially anonymous structs (containing the environment they
close over) expanded at compile time, and made to impl the Fn* family of
traits.

In your code, producing a bare closure from a match arm that could produce
other closures is not possible. You must use trait objects. The easiest
approach would probably be to just box each closure, and coerce it into a
trait object with a type annotation.

use std::env;
fn main() {
let args: Vec<_> = env::args().collect();
let op: Box<Fn(i32) -> i32> = match &args[1][..] {
"foo" => Box::new(|c: i32| c + 1),
"bar" => Box::new(|c: i32| c + 1),
"baz" => Box::new(|c: i32| c - 1),
"other" => Box::new(|c: i32| c - 1),
_ => return,
};
println!("{:?}", op(11));
}

There may be other ways to accomplish what you want. And if you aren't
closing over your environment, just use function pointers.

use std::env;
fn first_thing(c: i32) -> i32 {
c + 1
}
fn second_thing(c: i32) -> i32 {
c - 1
}
fn main() {
let args: Vec<_> = env::args().collect();
let op: fn(i32) -> i32 = match &args[1][..] {
"foo" => first_thing,
"bar" => first_thing,
"baz" => second_thing,
"other" => second_thing,
_ => return,
};
println!("{:?}", op(11));
}

Or if your situation ultimately allows for it, use generics in some way.


Reply to this email directly or view it on GitHub
#24036 (comment).

@ebfull

This comment has been minimized.

Contributor

ebfull commented Apr 4, 2015

Closures in rust used to be "boxed" so they acted similar to my first example solution.

@richo

This comment has been minimized.

Contributor

richo commented Apr 4, 2015

Great fix, and thanks for the explaination!

ebfull added a commit to ebfull/rust that referenced this issue Apr 4, 2015

Manishearth added a commit to Manishearth/rust that referenced this issue Apr 12, 2015

Rollup merge of rust-lang#24072 - ebfull:explain_closure_type_err, r=…
…pnkfelix

Also fixed bug calling .note() instead of .help()

See rust-lang#24036

bors added a commit that referenced this issue Apr 12, 2015

Auto merge of #24072 - ebfull:explain_closure_type_err, r=pnkfelix
Also fixed bug calling .note() instead of .help()

See #24036
@ebfull

This comment has been minimized.

Contributor

ebfull commented Apr 12, 2015

If you're satisfied the issue can be closed now.

@richo richo closed this Apr 12, 2015

@richo

This comment has been minimized.

Contributor

richo commented Apr 12, 2015

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment