[SOLVED] What is the point of diverging functions in Rust?


I have read several answers on SO already, and gathered these use-cases:

  • When a function panic!s
  • When a function has an infinite loop in it

But it is still unclear to me why we need to define the function like this:

fn func() -> ! {

if it will work the same way as this (without the exclamation sign):

fn func() {

and at the same time, why do we need to use ! in functions with infinite loops? It look like this signature doesn’t bring any real usage information.


The main difference between these signatures boils down to the fact that ! can coerce into any other type, and thus is compatible with any other type (since this code path is never taken, we can assume it to be of any type we need). It’s important when we have multiple possible code paths, such as if-else or match.

For example, consider the following (probably contrived, but hopefully clear enough) code:

fn assert_positive(v: i32) -> u32 {
    match v.try_into() {
        Ok(v) => v,
        Err(_) => func(),

When func is declared to return !, this function compiles successfully. If we drop the return type, func will be declared as returning (), and the compilation breaks:

error[E0308]: `match` arms have incompatible types
 --> src/main.rs:8:19
6 | /     match v.try_into() {
7 | |         Ok(v) => v,
  | |                  - this is found to be of type `u32`
8 | |         Err(_) => func(),
  | |                   ^^^^^^ expected `u32`, found `()`
9 | |     }
  | |_____- `match` arms have incompatible types

You can also compare this with definition for Result::unwrap:

pub fn unwrap(self) -> T {
    match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),

Here, unwrap_failed is returning !, so it unifies with whatever type is returned in Ok case.

Answered By – Cerberus

Answer Checked By – Jay B. (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *