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