First Draft: Callback For Matching Type
Quirin Schroll
qs.il.paperinik at gmail.com
Wed Jun 26 17:14:24 UTC 2024
On Monday, 24 June 2024 at 18:42:21 UTC, Richard (Rikki) Andrew
Cattermole wrote:
> On 25/06/2024 6:20 AM, Quirin Schroll wrote:
>> I guess I have implemented something like that:
>> https://d.godbolt.org/z/ePv4ndxeE
>>
>> If I understand you correctly, we share the vision of a tagged
>> union (I call them enum unions) as a type with certain members
>> (duck typing), not the instance of a particular template.
>>
>> But that’s where it seems our views diverge. In my
>> implementation, the tag also allows distinct same-type
>> options. (Options are discerned by tag, not by type.)
>
> I'm for this, however since I don't have member-of-operator I
> can't really do this in the way that I'd like.
>
> ```d
> expr.match {
> (:NameForTag var) => writeln(var);
> }
> ```
>
> Best to leave such support for future, unless a good proposal
> is given.
I now have implemented a `SumType` that is commutative,
associative, and idempotent, that is:
* the order of types does not matter: `SumType!(T, U)` is the
same as `SumType!(U, T)`,
* they auto-inline like alias sequences: `SumType!(Ts,
SumType!Us, SumType!Vs)` is the same as `SumType!(Ts, Us, Vs)`,
and
* duplicates don’t matter: `SumType!(T, T, Ts)` is `SumType!(T,
Ts)`.
Also, any `noreturn` is removed from a `SumType`, any `SumType`
with `void` becomes `void`, and any 1-ary `SumType` is just an
alias to that type.
Matching is done using one of the following functions:
* `matchByType`: Every handler must match with exactly one
option, possibly by conversion, otherwise error.
* `matchByTypeExact`: For every option, there must be a handler
with exactly that parameter type (possibly qualified).
* `matchByTypeDefault`: Same as `matchByType`, but the last
handler is applied to all options that couldn’t be handled by a
type-recognized handler.
* `matchByTypeExactDefault`: Same as `matchByTypeExact`, but the
last handler is applied to all options that couldn’t be handled
by a type-recognized handler.
### Example
```d
import std.stdio;
alias S1 = SumType!(int, string);
alias S2 = SumType!(long, string);
alias S = SumType!(S1, S2, bool);
static assert(is(S == SumType!(string, long, bool, int)));
auto x = S("abc");
auto h = x.matchByTypeExactDefault!(
(const string s) => s.length,
(bool b) => b ? 10 : 20,
(long x) => cast(size_t)x,
);
writeln(h); // 3
```
The `int` and `long` option can’t be handled by the `string` or
`bool` handler, thus the last handler is used.
Default handlers can be generic, but I’m getting a lot of
dual-context deprecation warnings unless I do some tricks.
Try it out here: https://d.godbolt.org/z/ndzd1z44e
More information about the dip.development
mailing list