Second draft: Sum Type by Struct
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Tue Sep 15 16:42:07 UTC 2026
On 16/09/2026 4:16 AM, Meta wrote:
> On Tuesday, 15 September 2026 at 16:06:22 UTC, Richard (Rikki) Andrew
> Cattermole wrote:
>>> So what happens if your DIP doesn't get accepted? Then you're SOL for
>>> PhobosV3 and have to rethink your design. Result types *themselves*
>>> don't need opCast or opUnwrapIfTrue. I think whatever design of
>>> PhobosV3 you have in mind should be kept separate from the design of
>>> the rest of the language. IMO Language design should drive library
>>> design, not vice- versa.
>>
>> Then it becomes a problem for Adam to solve.
>>
>> Either I get the problems solved that I can foresee, or its not worth
>> my limmited energy being put towards a library that I think isn't the
>> right way to go for D's standard library.
>
> The problem is that I feel like you're pessimizing the solutions to the
> current problems that exist *now* in favour of optimizing for solutions
> to future problems that don't exist yet, and may *never* exist.
>
>>>> I'm not convinced that this is the right way to solve it,
>>>> specifically because result types can have a much larger API and
>>>> internal logic than just a sumtype.
>>>
>>> Like what? I can't picture what you're thinking of.
>>
>> Future/Promise.
>>
>> These are result types.
>
> Well technically futures/promises and result types are both
> instantiations of the more general type class of monad, but I get what
> you mean. I've spent a lot of time working with futures/promises in
> Java, where they don't have opCast or opUnwrapIfTrue, and it wasn't a
> bad experience. But I'm curious how those two features would make it
> better.
Java has checked exceptions, there are interactions to other language
features allowing the cases I care about to not need special handling as
much. Also tbf I don't think await needs to evaluate to a value, and
instead be a yield (which isn't how other languages do it).
And languages like Scala have arbitrary "match" expressions:
```scala
def anotherFunc[T](response: Future[Either[Throwable, T]]) = {
response.onComplete {
case Failure(exception) => // process exception
case Success(value) => // process value
}
}
```
To me, trying to shoe horn matching into solving this means it is
overused. I prefer it to be a lot more constrained and explicit.
>>> I'm still not following. Having the .init value of the union being
>>> the tag = 0 (so the first variant is active) and the value stored
>>> being the .init value of the first type in the union, seems very
>>> logical and straightforward to me, in addition to being right in line
>>> with default initialization in the rest of the language, rather than
>>> having to complicate things with a special rule (which I see as NOT
>>> consistent with the rest of the language).
>>
>> Default initialization goes a step further, it specifies a lack of a
>> value. NaN, null these are key examples of it.
>>
>> None is the sumtype equivalent.
>
> Or again, just use typeof(null), which is that "lack of value" signifier
> that D already has. None is necessary in languages like Rust that don't
> have nullable references. In D, I see it as redundant.
I don't care too much if its a struct or that.
If it works, its equivalent.
However that was my explanation for why its special cased for default init.
More information about the dip.development
mailing list