Second draft: Sum Type by Struct

Nick Treleaven nick at geany.org
Sat Sep 5 16:02:08 UTC 2026


On Saturday, 5 September 2026 at 14:54:55 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
> On 06/09/2026 2:19 AM, Nick Treleaven wrote:
>> I also think an inferred sumtype result is surprising. What if 
>> I want the result type of the match expression to be inferred 
>> from the common type of all the results, how would I even 
>> write that? I think inferred common type should be the 
>> default, which is consistent with the `?` operator.
>
> You would add the casts to each arm.

That can be very verbose, and it's not *inferred*. Suppose the 
results are two class instances that inherit from a common base 
class. With your proposal, instead of getting a base class result 
type, I would get a sum type with the specific class types? I 
don't think that is good ergonomics.

>> There should be some way to manually specify the result type 
>> (which could be a sum type or not), the compiler is not always 
>> going to get the desired type whatever the rules. E.g. 
>> `expr.match -> int { ... }`. And it would indeed be nice to 
>> allow that result type to be another sum type.
> ```d
> int res = st.match {
> 	(T v) => "str",
> 	(U v) => 2
> }; // error
> ```
>
> Sumtypes widen on assignment, so that isn't an issue if you 
> want a sumtype.

What if I don't want a sumtype result, and I want to specify the 
type in one place? E.g. for my base class scenario.

> The match narrows to a single type, just like a sumtype of one 
> variant becomes that variant's type.
>
> It doesn't need more syntax, especially one that I haven't 
> spotted in other languages.

I did some research and you're right about other languages. I 
thought I had seen it somewhere. One reason some languages don't 
need it is (like Rust), they have reverse type inference. So they 
use the expected type:
```rs
     let r: i8 = match i { // specify i8 as result type
         n if n <= 1 => 1,
         n => 2,
     };
```

>> Also, using a new set of integer promotion rules (however 
>> nice) that aren't compatible with the C rules D inherited 
>> would need much stronger justification, and I doubt its a good 
>> idea. That plus sum type inference makes this DIP more 
>> complicated, and those could be added later in a separate DIP, 
>> if needed.
>
> I'm not working from C's promotion rules here, they are 
> primarily for math expressions which this is not.
>
> The rules I have worked based upon is the sumtype variants 
> where multiple integer types are errors for unnamed variants. 
> You can't know which variant to construct.
>
> So I want a rule that is neither lossy, nor will trigger this 
> error.
>
> And no, flow sensitive typing is not something you "add on 
> later". You do it up front or not at all.

That doesn't make sense. As I suggested, a valid design is to 
require there to be a common type for all arms, and if not you 
have to specify the result type manually, once. This design is 
simpler.

>>> TypeScript:
>>>
>>> ```typescript
>>> function evaluateArm(input: "a" | "b"): string | number {
>>>   switch (input) {
>>>     case "a":
>>>       return 42;        // This arm evaluates to a number 
>>> (int)
>>>     case "b":
>>>       return "hello";   // This arm evaluates to a string
>>>   }
>>> }
>> 
>> I don't know TS, but it looks like the `switch` above does not 
>> have a result type at all. BTW I am concerned that IIUC the 
>> above pattern (which you chose to quote), cannot be written 
>> with your proposal, because it doesn't support `return` in a 
>> match arm (i.e. returning from `evaluateArm` directly).
>
> I wanted statement arm bodies, it was in previous designs.
>
> But yeash there is nothing in the expression tree that would 
> allow it (that I could find, or aware of).
>
> It would be a massive addition.
>
> We could add it later on, since expression just becomes an 
> expression statement.

Not being able to use `return` in a match *expression* is 
understandable. Not having a match *statement* which can use 
`return` seems like a big omission IMO.

> The example is a simple example showing the flow sensitivity of 
> matching.

I think you missed my point that the TS example above seems to be 
just a switch *statement*, not an *expression*. Chat GPT says:

> TypeScript has only switch statements, not native switch 
> expressions.

And also, I'm not convinced that you have given an example of a 
switch expression inferring a sum type result type based on its 
match arms. The other 2 examples you gave may be using reverse 
type inference from the return type of the function. Do you have 
another example please? I.e. one with a statement afterwards.



More information about the dip.development mailing list