Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return #14

Closed
JacquelineCasey opened this issue Sep 13, 2023 · 4 comments
Closed

Return #14

JacquelineCasey opened this issue Sep 13, 2023 · 4 comments

Comments

@JacquelineCasey
Copy link
Owner

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...

@JacquelineCasey
Copy link
Owner Author

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:

  • Bottom can unify with any type to become that type. In other words,
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.

@JacquelineCasey
Copy link
Owner Author

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.

@JacquelineCasey
Copy link
Owner Author

Be aware of how never interacts with the short circuit boolean operators...

@JacquelineCasey
Copy link
Owner Author

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.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

1 participant