std.sumtype?
Paul Backus
snarwin at gmail.com
Sun Aug 29 19:51:30 UTC 2021
On Sunday, 29 August 2021 at 19:19:54 UTC, SealabJaster wrote:
> On Sunday, 29 August 2021 at 15:05:57 UTC, Paul Backus wrote:
>> ...
>
> It is also of course totally possible I'm not using sumtypes
> right, but I'm frequently in situations such as this:
>
> ```
> private string expectSingleIdentifier(Token tok, Expression[]
> exp)
> {
> string ret;
> exp[0].match!(
> (IdentifierExpression exp) { ret = exp.ident; },
> (_) { throw new Exception(...); }
> );
> return ret;
> }
> ```
For cases like this you can use `tryMatch`, which does not
require exhaustiveness and throws an exception at runtime if it
encounters a type with no handler:
```d
return exp[0].tryMatch!(
(IdentifierExpression exp) => exp.ident
);
```
> While in this case I still have to go through `match` in order
> to access the value, sometimes I simply want to do a type
> check, and going through `match` seems a bit overkill.
>
> I guess it's just a niche case (wanting to 'abort' on a bad
> value rather than keep going) I keep running into, likely a
> sign I need to change my mindset rather than anything else.
>
> Or I'm just using it as a wrong abstraction >;3
If "abort unless this `SumType` contains a particular type" is a
common pattern in your code I would suggest extracting it into a
helper function:
```d
void require(T, S)(S s)
if (isSumType!S)
{
s.match!(
(T t) {}
(_) { assert(0); }
);
}
```
But in general, I think this is the wrong approach. What I would
do instead is create a helper function like the following:
```d
Optional!T maybeGet(T, S)(S s)
if (isSumType!S)
{
return s.match!(
(T t) => some(t),
_ => no!T;
);
}
```
This narrows the set of cases you have to deal with from
"anything that could be in the `SumType`" to "either `T` or not
`T`", and from there you can handle the "not `T`" case however
you want--abort, throw an exception, etc.
The general principle here is ["Parse, don't validate."][1]
[1]:
https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
> In this specific case as well I don't believe I can use `return
> match!(...)` because I can't return anything in the "bad" case,
> since I'd then get an unreachable code error. Very minor yet
> annoying thing, but that's more a language issue rather than
> something inherent to SumType.
There is actually a workaround for this:
```d
return exp[0].match!(
(IdentifierExpression exp) => exp.ident,
function string (_) { throw new Exception("..."); }
);
```
Note the explicit return type of `string` on the second lambda.
The compiler will allow this, even though the lambda never
returns a `string`, because it never returns normally at all.
More information about the Digitalmars-d
mailing list