First Draft: Nominal Sum Types via `enum union` and `switch` Expressions

Dukc ajieskola at gmail.com
Fri Sep 25 20:44:26 UTC 2026


On Wednesday, 23 September 2026 at 22:15:09 UTC, Meta wrote:
> The tag can never be invalid. That's a core assumption of the 
> feature. If the user does some hacky stuff that messes with the 
> tag, they're responsible for making sure it's valid again 
> afterward.

It's certainly possible to specify the destructor that way. I've 
already written my main counterarguments to it, so I guess it's 
time we agree to disagree on this point.

>> Remember, existing `switch` statements allow this. Why 
>> `switch` expressions wouldn't?
>
> Because switch statements match against values, while switch 
> expressions match against patterns. Patterns only exist at 
> compile time, so a function call cannot be a pattern.

On second thought, maybe I agree with your assessment on function 
calls after all. Even if function calls would be allowed, only 
CTFE calls would work and the results of those can be declared 
beforehand with `enum`.

Template instancing should still be allowed inside the body 
though, that template instance might be an alias referring to a 
`case` field.

>
> Also, since you're omitting the types here, they would have to 
> be inferred by the compiler. I *think* it can infer them, and 
> the inferred type would have to be double,

Well, `long` in case of both `a` and `b` being longs. I admit I 
didn't get the result typing as I wished in this example.

I managed even worse in my "better" example in the next post 
since the `case (float aNum, float bNum)` will match all 
non-error cases, which means nothing would be left to match for 
the wildcard `case (aNum, bNum)`!

> but that would be very confusing for the reader. There are a 
> lot of issues with this suggestion.

Had another look how OCaml does it. It does support wildcards, 
but they do not work as I proposed. Instead, they are essentially 
`default` cases with a variable name, the variable binding to 
result of the matched expression. I think that's a good 
alternative.

Why would we want it if we already have the `default` case? 
Logical consistency. In the future, we can probably do
```d
switch(someOptionalInt)
{   case just 0 () => "zero",
     case just(x) => "value",
     case nothing() => "no value"
}
```
. Note that the syntax can't be `case just(0)`, because then we 
couldn't know whether `x` in `just(x)` is a value to match (an 
`enum` identifier) or a variable declaration. It'd make sense 
that the syntax for the top level case would work similarily, 
which leads to:

```d
switch(someNormalInt)
{   case 0 () => "zero",
     case x => "value"
}
```




More information about the dip.development mailing list