How type safety is guaranteed?

rust

Solution

Let's look at that piece of code more closely:

loop {
    // ... some code omitted ...
    let num = match input_num {
        Some(num) => num,
        None      => {
            println!("Please input a number!");
            continue;
        }
    };
    // ... some code omitted ...
}

The match statement is located inside a loop, and there are several constructs in the language which help control the looping process. `break` exits from a loop early, while `continue` skips the rest of the code in the loop and goes back to its beginning (restarts it). So this match above basically can be read basically as "Check the number, and if it is there, assign it to `num` variable, otherwise output a message and restart from the beginning".

The behavior of "otherwise" branch is important: it ends with a control transfer operation, `continue` in this case. The compiler sees `continue` and knows that the loop is going to be restarted. Consequently, it does not really matter what value this branch yields, because it will never be used! It may as well never yield anything.

Such behavior often is modeled with so-called bottom type, which is a subtype of any type and which does not have values at all. Rust does not have subtyping (essentially), so such type is deeply magical. It is denoted as `!` in type signatures:

fn always_panic() -> ! {
    panic!("oops!")
}

This function always panics, which causes stack unwinding and eventual termination of the thread it was called in, so its return value, if there was one, will never be read or otherwise inspected, so it is absolutely safe not to return anything at all, even if it is used in expression context which expects some concrete type:

let value: int = always_panic();

Because `always_panic()` has return type `!`, the compiler knows that it is not going to return anything (in this case because `always_panic()` starts stack unwinding), it is safe to allow it to be used in place of any type - after all, the value, even if it was there, is never going to be used.

`continue` works exactly in the same way, but locally. `None` branch "returns" type `!`, but `Some` branch returns value of some concrete numeric type, so the whole match statement is of this numeric type, because the compiler knows that `None` branch will lead to control transfer, and its result, even if it had one, will never be used.

Problem

Just skimming through the Rust guide (guessing game), this code fragment doesn't seem right to me: ``` let num = match input_num { Some(num) => num, None => { println!("Please input a number!"); continue; } }; ``` How does type inference of `num` work in this scenario? The first match case obviously return a number, whereas the second match case is just `println` & `continue` statement, which doesn't return anything(or return `()`). How does the compiler assume it's type safe?

Original source