Sum type, the D way
deadalnix
deadalnix at gmail.com
Tue Nov 29 18:24:37 UTC 2022
While I think I made it fairly clear that my position is that
sum types aren't what D should focus on at this time, I have the
feeling this is going to be ignored, and that we are going to
roll out something regardless, so I might as well put a few
things here to make sure we at least end up with something that
fit within a language and its spirit.
We already have a sum type like feature in D: enum. Wait what?
Well enum, short for enumerations, are types that specify a set
of value a variable can take. sum types are just an extension of
that idea: instead of simply providing a set of values, they also
allow to provide entire classes of allowable values, types.
So we could simply have:
```d
enum MySumType {
int,
bool,
MyStruct,
// ...
}
```
D is a system programming language, which means one needs to be
able to specify how the bits are layed down. Thanksfully, enums
already provide us with a syntax to provide the backing type for
our enum, and that won't be enough here. But just like ranges, we
can duck type the whole thing the following way:
```d
enum MySumType : BackingType {
int,
bool,
MyStruct,
// ...
}
// We assume that MySumType is able to generate some magic enum
internally,
// such as MySumType.__Kind is an enum with the different types
in there.
struct BackingType {
MySumType.__Kind kind;
union {
This,
That,
TheOther,
}
// opAs is used by the compiler to extract the right union
member.
auto opAs(MySumType.__Kind T)() {
// Return the right element in the union.
}
}
```
The BackingType can be made 100% optional and compiler generated
when none is provided.
This is obviously a half assed proposal, as I can already see
ambiguity in the syntax thinking of it for minutes, but my goal
here is for people to think a bit about what that feature looks
like *FOR D*.
Without a coherent design we only get exploding complexity and
things that don't fit together. We have an exemple of that in D
currently that is definitively affecting that design (which is
why we are finding ourselve looking at introducing a new feature
rather than generalizing an existing one): D is completely
schizophrenic about whether enum are a closed or an open set.
`final switch` assumes closed, but binary operators such as `|`
assume open.
Well, if forces us to answer that question (or to ignore it and
add to the pile of bear traps) so I will answer it: the set of
allowable value must be closed, as this is the construct that
naturally extends towards supporting sum types.
But you'll ask me, we have these open set, what do we do about
them? We do this:
```d
enum CloseSet { A, B }
enum OpenSet { A, B, ... }
```
Voila, problem solved. When using the first one, operator like
`|` either fall back to the base type, or plain don't work. When
using the second one, final switch must, in addition to handled
all the value, provide a default label.
Voila, now what about pattern matching these thing? Like this:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2392r0.pdf
More information about the Digitalmars-d
mailing list