What‘s the difference between functions with no return value and diverging functions


#1

I’m a beginner of this language.
I can’t understand why are there these two kind functions.
such as,
foo() {}
bar()->!{}

What is the special usage of diverging function


#2

fn foo() { ... } syntax doesn’t mean it returns no value: it is a shorter form of fn foo() -> () { ... } i.e. the function returns the () type. (This is equivalent to void in C/C++.)

A diverging function is guaranteed to never return, i.e. bar(); println!("this never prints");. An example of a diverging function is fn bar() -> ! { panic!() } or fn bar() -> ! { loop {} }.


#3

thanks for your help!
but I can’t figure out what a use case must use diverging functions.
So have you ever had to use them other than those renturn ‘()’ ?
I don’t understand their design purpose.


#4
fn must_return_a_string(condition: bool) -> String {
    if condition {
        String::from("something expensive")
    } else {
        panic!("condition can't be false!");
        // now what?
    }
}

Without diverging functions, there’s no sane way to fill in the “now what?” part of the above. The compiler wouldn’t have any way to figure out that panic! never returns, and thus the else branch doesn’t need a result.


#5

thank you, but it’s a bit hard to understand for me.

I think “must_return_a_string” is a normal function,

fn must_return_a_string() -> String { panic!("condition can't be false!"); }
the code above,this function does not return.is it a diverging function?
I feel very confusion as a beginner.


#6
fn must_return_a_string() -> String {
    panic!("condition can't be false!");            
}

Ok, this diverges in practice, but doesn’t indicate this via the signature. When you call a function, Rust only ever looks at the signature; it never inspects the body of the function to work out what it does. As such, although this will always diverge at runtime, the compiler doesn’t know that.

On the other hand:

fn must_return_a_string() -> ! {
    panic!("condition can't be false!");            
}

This always diverges, and the compiler knows it.


#7

Thank you for your patience and helpful guidance.
Do we really need another “strange” kind of function in practice?
Let the compiler can identify, will make the code more safe, or are there other benefits?

Are there some use cases make the diverging functions irreplaceable or be a better choice than others, after all, all kinds of functions can panic , can not return.
thanks again.


#8

We need them because if we didn’t have them, we couldn’t write functions like must_return_a_string which can fail at runtime and otherwise have to return something. Well, we could, but we’d have to give up on the compiler checking that we return a value when we need to.


#9

Now I understand.
And I found it looks like Exception in other languages, e.g. java.
they cause the program crash out and display the message.
Rust use function,but java use class.
So "Exception" in Rust need to solve the mismatch of the return values. It need another kind of
function to pass the type check.
that’s right?


#10

Broadly.

Exceptions represent abnormal control flow, allowing you to effectively jump out of a function without performing a normal return.

Diverging in Rust, however, doesn’t mean “abnormal return”, it means “won’t return at all”. For example, calling abort diverges because it tells the operating system to just kill the whole process.

But broadly, yes; where Java would see you throwing an exception and say “you obviously don’t need to return anything from this point, because you’ll unwind”, Rust instead marks the path as diverging.

To put it in other words: Java knows that throw new Exception(); is a diverging statement, but has no way of marking an actual method as diverging. Instead of having a special construct for this, Rust just lets you mark functions as diverging, which then has more or less the same effect.