rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.21k stars 12.56k forks source link

Unclear Error Message in Philosopher Example #25488

Closed StefanoD closed 8 years ago

StefanoD commented 9 years ago

This code...

use std::thread;

struct Philosopher {
    name: String,
}

impl Philosopher {
    fn new(name: &str) -> Philosopher {
        Philosopher {
            name: name.to_string(),
        }
    }

    fn eat(&self) {
        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

fn main() {
    let philosophers = vec![
        Philosopher::new("Baruch Spinoza"),
        Philosopher::new("Gilles Deleuze"),
        Philosopher::new("Karl Marx"),
        Philosopher::new("Friedrich Nietzsche"),
        Philosopher::new("Michel Foucault"),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        thread::spawn(move || {
            p.eat();
        });
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}

... leads to:

src/main.rs:39:11: 39:17 error: type `()` does not implement any method in scope named `join`
src/main.rs:39         h.join().unwrap();
                         ^~~~~~
error: aborting due to previous error
Could not compile `Philosopher`.

Actually the error lies in line 35 in the semicolon }); at the end:

thread::spawn(move || {
            p.eat();
        });
pnkfelix commented 9 years ago

That's an interesting failure mode; i.e. you were forced to say the Vec type explicitly, but the language lets you leave out the element type via Vec<_>. And then it inferred that the element type is () since that is the result of the map callback, due to the semicolon after thread::spawn that was noted in the description...

error reporting for type inference errors is a notoriously difficult area, but we probably could do more here. Even just special casing (), since the presence/absence of a semi-colon is an easy thing to overlook, might be useful.

(by "special-casing ()", I mean something hacky like tracking when we infer a unification-variable to be (), and then if that ends up being involved with a type error down the road, then report the chain of inference decisions that led to the () being introduced.)

ElderThorin commented 9 years ago

Removing the ; at the end of the

thread::spawn(move || {
        p.eat();
    });

(the current state of the documentation does not have a semicolon in that location)

results in the following slightly different compile error, and thus the current version of the dining philosophers program does not compile. As I'm just trying to follow the examples for the first time, I have no clue why unwrap would or would not be available.

main.rs:39:9: 39:24 error: attempted access of field `unwrap` on type `core::result::Result<(), Box<core::any::Any + Send>>`, but no field with that name was found
main.rs:39         h.join().unwrap;
                   ^~~~~~~~~~~~~~~
error: aborting due to previous error

It's possible this should be a separate issue, I'm not certain.

Note: this fails in this way with the Windows 64bit 1.0.0-beta build (built 2015-04-02)

pnkfelix commented 9 years ago

@tlinderh it looks to me like you removed the () on the end of .unwrap(); as well, turning an attempted method call to an .unwrap() method into an a field access on the (non-existent) .unwrap field.

Update: (If you are using something other than the source code in this ticket description as the basis for your comment, then you should probably include a link in your comment (and, as you mention, perhaps file a separate issue)...)

ElderThorin commented 9 years ago

I'm not certain how I ended up pasting in a version without () at the end of unwrap(). That's not even the correct error message. It should read '... does not implement any method in scope named 'unwrap'. This was after copy-pasting the code directly out of the rust dining philosophers example (the last version of it listed.)

http://doc.rust-lang.org/stable/book/dining-philosophers.html

It works fine in the rust web workshop thing, but it doesn't work with the windows 6bit .0.0-beta install on my machine.

Opened new issue #25649 for this issue.

benfleis commented 9 years ago

I just ran into this, and what isn't clear from either the book, or the error, is why a semi-colon isn't expected. Perhaps this is obvious to Rustaceans, but as a complete newcomer, it's counter intuitive to not have a ; in that location, and the produced error left me scratching my head until I gave up and diff'd my code versus the given code from the book.

Thus, +1 on an improved error message, if it's reasonable. And +1 on a bit of explanation in the book -- if the semi-colon changes the return type of a lambda, it seems worthy of more :)