RUST — Why would I use divergent functions?

Yang Nana
3 min readApr 11, 2018

--

Copied from

Rust has some special syntax for ‘diverging functions’, which are functions that do not return:

fn diverges() -> ! {
panic!("This function never returns!");
}

panic! is a macro, similar to println!() that we’ve already seen. Unlike println!(), panic!()causes the current thread of execution to crash with the given message. Because this function will cause a crash, it will never return, and so it has the type ‘!’, which is read ‘diverges’.

If you add a main function that calls diverges() and run it, you’ll get some output that looks like this:

thread ‘main’ panicked at ‘This function never returns!’, hello.rs:2

If you want more information, you can get a backtrace by setting the RUST_BACKTRACE environment variable:

$ RUST_BACKTRACE=1 ./diverges
thread 'main' panicked at 'This function never returns!', hello.rs:2
Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
hello::diverges
at ./hello.rs:2
hello::main
at ./hello.rs:6

If you want the complete backtrace and filenames:

$ RUST_BACKTRACE=full ./diverges
thread 'main' panicked at 'This function never returns!', hello.rs:2
stack backtrace:
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
8: 0x7f402773d1d8 - __rust_try
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
10: 0x7f4027738a19 - main
11: 0x7f402694ab44 - __libc_start_main
12: 0x7f40277386c8 - <unknown>
13: 0x0 - <unknown>

If you need to override an already set RUST_BACKTRACE, in cases when you cannot just unset the variable, then set it to 0 to avoid getting a backtrace. Any other value (even no value at all) turns on backtrace.

$ export RUST_BACKTRACE=1
...
$ RUST_BACKTRACE=0 ./diverges
thread 'main' panicked at 'This function never returns!', hello.rs:2
note: Run with `RUST_BACKTRACE=1` for a backtrace.

RUST_BACKTRACE also works with Cargo’s run command:

$ RUST_BACKTRACE=full cargo run
Running `target/debug/diverges`
thread 'main' panicked at 'This function never returns!', hello.rs:2
stack backtrace:
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
8: 0x7f402773d1d8 - __rust_try
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
10: 0x7f4027738a19 - main
11: 0x7f402694ab44 - __libc_start_main
12: 0x7f40277386c8 - <unknown>
13: 0x0 - <unknown>

A diverging function can be used as any type:

let x: i32 = diverges();
let x: String = diverges();

It has several uses. It can be used for functions which are designed to panic or exit the program. panic!() itself is one such function, but it can also be applied to functions which wrap panic!(), such as printing out more detailed error information and then panicking.

It can also be used for functions that never return. If a function goes into an infinite loop, such as the main loop of a server, and thus never returns, it could be defined this way.

Another possible use would be a wrapper around the Unix exec family of functions, in which the current process is replaced with the one being executed.

It is useful to have such a type because it is compatible with all other types. In order to be type safe, Rust has to ensure that all branches of a match or if statement return the same type. But if there are some branches that are unreachable or indicate an error, you need some way to throw an error that will unify with the type returned by the other branches. Because ! unifies with all types, it can be used in any such case.

--

--

Yang Nana
Yang Nana

No responses yet