Closed JacquelineCasey closed 1 year ago
Trying to decide if return should be an expression or a statement.
In Rust, it's an expression, although of course you almost always use it in a context where it could easily be turned into a statement by the addition of a semicolon.
The only benefit of expressional return that I understand is that you can omit the wrapping block if you are early returning from a match statement. To be fair, that is a nice ergonomic thing.
I am actually going to make it an expresssion, for a weird reason. We want return to have a type, and expressions have types while statements do not. The type might be called "diverging," "never," or "bottom." It actually exhibits some special rules:
val a: i32 = return "hello world";
Is allowed, even though it is kinda weird code. Something more sane is:
val a: i32 = if b == c {
1000
}
else {
return "hello world"
}
Actually, annoyingly, that should compile even if the return has a semicolon, or if it is nested deep in some other set of branches that are guaranteed to diverge. We really need to do some sort of reachability analysis... the second rule is something like - if a block contains a never
type, then the type of the block decays to never
.
We are going to want to do this analysis at some point, and I think the never
type is very interesting actually! Zig has some information on what it can be used for, though they call it noreturn
.
For instance, we could then add unreachable
as a keyword. Zig's @panic
is a builtin function, but it also returns noreturn
, which seems like the right behavior.
Be aware of how never
interacts with the short circuit boolean operators...
We could special case while true
to be never
as well.
Another interesting use of never
: Result<i32, never>
for those weird generic situations when you need a result (perhaps a callback is supposed to give a result but you know for a fact that the error part never happens). Rust does this, but it calls this special type Infallible
. Interestingly, it is implemented as the zero variant enum.
Huh, I never noticed that the zero field tuple (product type) was the unit type and the zero variant enum (sum type) was the bottom type.
Allow the return keyword in functions. I am not sure if return should be a statement or an expression.
One concern is type checking - ideally a branch that returns should have some sort of
diverges
type, which can coerce to any other type. Does this only work if we use return as a statement? Should using return as an expression statement be allowed in this case? I guess dead code is ok if it is being actively worked on or the live code is just a test, but it might necessitate some sort of analysis that says that a branch yields the bottom type if it is guaranteed to always hit a return...