6

I came across this function in rust:

#[no_mangle]
 pub extern "C" fn _start() -> ! {
    loop {}
}

From the answer here: What does "-> !" means in Rust I understood it never returns.

What is the difference between above function and the below without any return?

#[no_mangle]
 pub extern "C" fn _start() {
    loop {}
}

I'm able to compile both.

RRON
  • 1,037
  • 3
  • 12
  • 32

1 Answers1

4

A Rust function with no explicit return type is equivalent to one whose return type is explicitly marked () (pronounced "unit"). This is the equivalent to void in the C++-family of languages. So

fn example() {
    loop {}
}

is equivalent to

fn example() -> () {
    loop {}
}

It effectively "ignores" the return value. So if we have a function bar() which returns i32, then

fn foo() -> i32 {
    bar()
}

is a function returning the result of bar, while

fn foo() {
    bar()
}

is a function which calls bar and then throws away its return value.

! (pronounced "never") is a bit special in Rust. A value of type ! can be assigned to a variable of any type. On the other hand, () is an ordinary type. So if we called the ! version of our example function in, say, one arm of a match statement, then it would happily coexist with whatever the return type of the match is.

match foo() {
    Some(x) => 0,
    None => example(),
}

example will agree with this match, since it will loop forever (or panic) and never return. But the () version of example will fail to compile, since () and i32 are not the same type.

In summary, if you can explicitly mark a function as returning !, then you should do so. A return type of ! is always better than one of (), since the former can be converted to the latter.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • It might also be worth pointing out that a value of type `!` can never be created, which is _why_ it is safe to convert it to any other type. – cdhowie Jun 30 '22 at 02:17
  • Also, since a value of type `!` can never be created, there is an (experimental, for now) feature that allows you to turn a refutable pattern into an irrefutable one if all but one patterns require a value of type `!`. For instance, if `a: Result`, one could do something like `let Ok(v) = a;`. – jthulhu Jun 30 '22 at 06:17