? in main and tests - The Edition Guide

# `?` in `main` and tests

Rust's error handling revolves around returning `Result<T, E>` and using `?` to propagate errors. For those who write many small programs and, hopefully, many tests, one common paper cut has been mixing entry points such as `main` and `#[test]`s with error handling.

As an example, you might have tried to write:

    use std::fs::File;

    fn main() {
        let f = File::open("bar.txt")?;
    }

Since `?` works by propagating the `Result` with an early return to the enclosing function, the snippet above does not work, and results today in the following error:

    error[E0277]: the `?` operator can only be used in a function that returns `Result`
                  or `Option` (or another type that implements `std::ops::Try`)
     --> src/main.rs:5:13
      |
    5 |     let f = File::open("bar.txt")?;
      |             ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
      |
      = help: the trait `std::ops::Try` is not implemented for `()`
      = note: required by `std::ops::Try::from_error`

To solve this problem in Rust 2015, you might have written something like:

    // Rust 2015

    use std::process;
    use std::error::Error;

    fn run() -> Result<(), Box<Error>> {
        // real logic..
        Ok(())
    }

    fn main() {
        if let Err(e) = run() {
            println!("Application error: {}", e);
            process::exit(1);
        }
    }

However, in this case, the `run` function has all the interesting logic and `main` is just boilerplate. The problem is even worse for `#[test]`s, since there tend to be a lot more of them.

In Rust 2018 you can instead let your `#[test]`s and `main` functions return a `Result`:

    // Rust 2018

    use std::fs::File;

    fn main() -> Result<(), std::io::Error> {
        let f = File::open("bar.txt")?;

        Ok(())
    }

In this case, if say the file doesn't exist and there is an `Err(err)` somewhere, then `main` will exit with an error code (not `0`) and print out a `Debug` representation of `err`.

## More details

Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not magic. It is all backed up by a `Termination` trait which all valid return types of `main` and testing functions must implement. The trait is defined as:

    #![allow(unused)]
    fn main() {
    pub trait Termination {
        fn report(self) -> i32;
    }
    }

When setting up the entry point for your application, the compiler will use this trait and call `.report()` on the `Result` of the `main` function you have written.

Two simplified example implementations of this trait for `Result` and `()` are:

    #![allow(unused)]
    fn main() {
    #![feature(process_exitcode_placeholder, termination_trait_lib)]
    use std::process::ExitCode;
    use std::fmt;

    pub trait Termination { fn report(self) -> i32; }

    impl Termination for () {
        fn report(self) -> i32 {
            use std::process::Termination;
            ExitCode::SUCCESS.report()
        }
    }

    impl<E: fmt::Debug> Termination for Result<(), E> {
        fn report(self) -> i32 {
            match self {
                Ok(()) => ().report(),
                Err(err) => {
                    eprintln!("Error: {:?}", err);
                    use std::process::Termination;
                    ExitCode::FAILURE.report()
                }
            }
        }
    }
    }

As you can see in the case of `()`, a success code is simply returned. In the case of `Result`, the success case delegates to the implementation for `()` but prints out an error message and a failure exit code on `Err(..)`.

To learn more about the finer details, consult either the tracking issue or the RFC.