Reading through the Rust book, I came across an interesting topic — divergent functions:
Rust has some special syntax for ‘diverging functions’, which are functions that do not return:
fn diverges() -> ! { panic!("This function never returns!"); }
A diverging function can be used as any type:
let x: i32 = diverges(); let x: String = diverges();
What would be the use cases of a divergent function? The book says that
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!
That makes sense, but I can't think of where else a divergent function would be of use and it seems very localized to just panic!
. I know there must be some useful scenarios out there for why they introduced divergent functions. Where would I likely see divergent functions in Rust?
The benefit of divergent thinking is that it encourages people to think from multiple perspectives to open theoretically limitless options, followed by sense-making, ultimately resulting in more innovative solutions or breakthrough possibilities to address the challenge at hand.
“Divergent thinking is also called lateral thinking. It is a thought process of coming up with varied creative ideas to overcome a problem and generate a solution.” Divergent thinking is often a non-restricted, non-linear, and free-flowing chain of thoughts to let new ideas come as and when they occur.
Because some of the resulting ideas are original, divergent thinking represents the potential for creative thinking and problem solving. Originality is not synonymous with creative thinking, but originality is undoubtedly the most commonly recognized facet of creativity.
As discussed above, divergent (or creative) thinking is an activity that leads to new information, or previously undiscovered solutions. Some problems demand flexibility, originality, fluency, and inventiveness, especially those for which the individual must supply a unique solution.
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.
There is an interesting RFC (and discussion) at the moment that argues (in part) for expanding the places where !
can be used, arguing that it should be treated as a full fledged type like ()
is; !
being a type with no values that unifies with all other types, while ()
being a distinct type with a single value. I'm not sure I agree with the full RFC, but the discussion of treating !
as a full-fledged type is interesting and I think could be proposed separately from the rest of the RFC.
Update: Since I wrote the above, the part of the RFC about promoting !
to a full fledged type was split into a separate RFC and merged, and is in the process of being implemented (currently available in nightly builds behind a feature gate). As a full-fledged type, it can be used in more contexts, such as in Result<T, !>
indicating a result that can never fail, or Result<!, E>
as one that can never succeed. These are useful in generic contexts; if you have some trait that requires a method to return a result, but for that particular implementation it can only possibly succeed, you don't need to fill in some dummy error type.
As you quoted from the book, Rust's bottom type is used to specify functions that do not return. This includes:
panic!()
main()
), such as exit(), whose signature is pub fn exit(code: i32) -> !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With