Skip to content
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

The Book should document, and use, the idiomatic way to exit unsuccessfully without panicing #38300

Closed
zackw opened this issue Dec 11, 2016 · 6 comments

Comments

@zackw
Copy link
Contributor

zackw commented Dec 11, 2016

main in a Rust program returns no value, AFAICT (I can't find any reference documentation for main, but all the examples just do fn main() { ). All of the examples in The Book either panic or exit normally (even in error cases), and process exit statuses are not mentioned anywhere. This is Wrong. The Book should document the idiomatic way to exit unsuccessfully without panicing, and all of the example programs should use that method when appropriate.

Take for instance this example from https://doc.rust-lang.org/book/error-handling.html#parsing-integers:

use std::num::ParseIntError;

fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
    match number_str.parse::<i32>() {
        Ok(n) => Ok(2 * n),
        Err(err) => Err(err),
    }
}

fn main() {
    match double_number("10") {
        Ok(n) => assert_eq!(n, 20),
        Err(err) => println!("Error: {:?}", err),
    }
}

The Err case in main should cause the program to exit unsuccessfully, but without panicing.

Related, I can't figure out what the idiomatic way to exit unsuccessfully without panicing actually is. The only thing I've found is std::process::exit, whose documentation makes it sound like it is not the correct thing to use (e.g. dire warnings about not running destructors).

The basic grep exit-status convention should be mentioned at some point (code 0 = no error, matches found; code 1 = no error, no matches found; code 2 = error occurred).

@nagisa
Copy link
Member

nagisa commented Dec 11, 2016

std::process::exit is indeed the idiomatic way to exit the program early, however nothing precludes using it to return “cleanly”. For example:

fn main() {
     ::std::process::exit(match run_your_app() {
        Ok(0) => 1, // no matches
        Ok(_) => 0, // some matches
        Err(someerr) => {
           report(someerr); 2 // return whatever you want depending on the error
        }
     });
}

@zackw
Copy link
Contributor Author

zackw commented Dec 11, 2016

@nagisa That's reasonably tidy, and I can see how it's safe in a single-threaded program (everything needing destroying must have been destroyed by the time run_your_app returns, with the possible exception of stdout and stderr). But what about multithreaded programs? "Make sure to join all threads before returning from run_your_app" might be good enough until you start worrying about invisible thread pools in libraries ...

@nagisa
Copy link
Member

nagisa commented Dec 11, 2016

Drop impl for non-detachable (i.e. daemonizable) threads and their pools ought to join on your threads already. If they do not and you rely on your threads not dying before completion, you have an implementation bug even without using process::exit.

@steveklabnik
Copy link
Member

The book is no longer being actively developed; we're working on the second edition over here: https://github.com/rust-lang/book

Would you mind opening an issue on that repo? I'm not totally convinced that this belongs in the book, but let's talk about it over there.

@ollie27
Copy link
Member

ollie27 commented Dec 12, 2016

I think this is about more than just the book. The docs for std::process::exit are in desperate need of good examples.

@steveklabnik
Copy link
Member

We already have a ticket for that: #29370

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants