Built-in sumtypes, case and noreturn: why block enders should be expressions.
FeepingCreature
feepingcreature at gmail.com
Mon Oct 24 06:20:15 UTC 2022
I finally added bottom types to neat (https://neat-lang.github.io
, but it's not on a released tag yet). For context, bottom types
are called `noreturn` in D. The main motivation for me was that
it enables a very neat idiom for built-in sumtypes. Since someone
raised the idea of making sumtypes built-in to Walter, I want to
preemptively explain how this works:
```
(int | string) foo;
...
int i = foo.case(int i: i, string s: return null);
```
Now, this used to be a built-in syntax. It seems intuitively
obvious that you should be able to discard a branch of the `case`
by just returning out of the function entirely. But the way that
it *actually works* now, is that **all** block enders, ie.
`return`, `break` and `continue`, instead of statements are just
- expressions of type `bottom`. And bottom unifies with every
type :) so these expressions don't add any type of their own to
the `case` expression type - *except* if they are the only
expression in the `case`, in which case the type of the whole
`case` expression is `bottom`, as it should be.
The reason I love this so much is because it's an easy way in the
typesystem to capture our intuition about these statements; which
is that we can ignore them because they don't ever evaluate to an
actual value. And in one stroke, it also enables other idioms,
like `foo.case(string s: exit(1))`, which we would expect to work
the same, for the same reason.
So, you know, we already have noreturn, so if you ever implement
built-in sumtypes in D, keep this in mind. :)
PS: hilariously, with this change the following is entirely valid
code:
```
int foo() { return return return 3; }
```
More information about the Digitalmars-d
mailing list