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