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