// HACKER NEWS — CYBERSECURITY
Stabilizing Rust's Never Type
A function's return type is supposed to indicate the kind of data that it
produces.
Rust's "never" type, which is
denoted by an exclamation mark ("!"), is the type the language uses to mark
a function that never returns and other places where a value can never occur. For
a long time, the never type was used internally by the compiler, but was
considered an unstable feature. On
August 24, after more than two years of work,
Rust-compiler-contributor "waffle" finally managed to stabilize the type. It
took so long, in part, because it involved a small breaking
change to previous Rust editions, which the compiler maintainers needed to
ensure did not impact much real code.
(Note: Rust also uses exclamation marks to indicate calls to macros. The way the
syntax is constructed, a place where it is valid to use the never type is not a
valid place to put a macro invocation and vice versa.)
There are two reasons that Rust has a never type, one practical and one
philosophical. The practical reason is that it allows for more efficient generic
code. For example, consider the
FromStr trait in the standard library, which is used for types that
can be instantiated from a string:
FromStr::from_str() either returns a converted result, or a custom
error type. For example, attempting to convert "foo" into an integer will return
a
ParseIntError. But some types have an infallible conversion. For
example, it is always possible to convert a string into a
ByteString. That implementation of FromStr could set
Err to be the never type. Then the compiler would know that the
error branch of the returned Result is never present, and could
optimize out all of the code that touches it or checks for it.
The philosophical reason involves correct type inference. In Rust, constructs
such as if statements and while loops are expressions; their results can be
assigned to a variable. The compiler needs a type to infer for the result of an
infinite loop, if the programmer writes one. That shouldn't come up often in
real code, but it turns out to simplify type inference to be able to treat that
case uniformly, rather than adding special rules to handle it.
In particular, the never type has a useful property for simplifying code: it
automatically coerces to any other type. This sounds strange, but it is
safe, since the never type represents the "result" of a computation that will
never produce a value. So, anywhere that the code claims to have a value of the
never type, the compiler knows that it can't possibly reach
that code, and therefore it's safe to ignore it. This is a form of
type-system-driven dead-code elimination.
LWN has always been about quality over quantity; we need your help
to continue publishing in-depth, reader-focused articles about Linux
and the free-software community. Please subscribe today to support our work
and keep LWN on the air; we are offering a free one-month trial subscription to get you started.
For both of these reasons, Rust programmers have wanted to be able to use the
never type in stable versions of the language. Making that happen
required resolving a particularly thorny corner case.
Because of the way that conversions from the never type to other types are
implemented, the compiler can sometimes end up in a situation where it cannot
naively infer the concrete type of an expression. Consider this example, which
defines an anonymous function (using ||, which is like
Python or LISP's lambda) that never returns, and then calls it in a way
that expects a concrete error type (using the
? operator):
That infinite loop is given a type of ! which is then implicitly
converted to whatever the function is supposed to return. But since the function
is defined locally and not given an explicit type, the compiler does not have
sufficient information to say what that type is.
The problem could be fixed by giving the function an explicit return type: