sumtype 0.8.3

Paul Backus snarwin at gmail.com
Mon Mar 4 00:46:12 UTC 2019


On Sunday, 3 March 2019 at 14:32:55 UTC, Jacob Shtokolov wrote:
> On Monday, 25 February 2019 at 20:31:43 UTC, Paul Backus wrote:
>>   - Pattern matching, including support for structural 
>> matching (★)
>
> What is the main difference between 'match()' in this library 
> and 'visit()' in std.variant?

I'm glad you asked! There are quite a few differences between 
SumType's `match` and Algebraic's `visit`. For a comprehensive 
answer, I recommend reading and comparing the documentation for 
both [1][2], but I'll do my best to highlight some of SumType's 
biggest advantages here.

1. `match` uses static introspection to determine whether a 
handler can be used for a particular type. This allows it to be 
much more flexible that `visit`, which requires an exact match. 
For example:

     alias CharSequence = SumType!(char[], immutable(char)[]);

     char firstChar(CharSequence seq) {
         return seq.match!((const(char)[] arr) => arr[0]);
     }

Because both `char[]` and `immutable(char)[]` can be passed to a 
function that accepts `const(char)[]`, `match` allows you to use 
the same handler for both types, even though it doesn't match 
either one exactly. With `visit`, that's not allowed.

2. `match` will also allow you to leave out type annotations 
altogether, if it can figure out what the right matches are from 
the function bodies. For example:

     alias Value = SumType!(int, double, string);

     void double(Value v) {
         v.match!(
             (ref number) { number *= 2; }
             (ref array) { array ~= array; }
         );
     }

In the code above, `match` is able to tell (using 
`__traits(compiles)`) that you can only use `*=` with a number, 
so that function should be used for the int and float members, 
and you can only use `~=` with an array, so that function should 
be used for the string member. This is what's referred to as 
"structural matching" in the announcement post, though now that I 
think of it, "introspection-based matching" is probably a better 
name.

Once again, `visit` can't do this at all--if you try to write the 
equivalent of the above code, it simply won't compile.

3. `match` gives you an error if you pass it a handler that 
doesn't match *any* of the types in your SumType. For example, 
the following code won't compile:

     alias Value = SumType!(int, double);

     int floor(Value v) {
         return v.match!(
             (int i) => i,
             (double d) => cast(int) d,
             (string s) => cast(int) s.to!double // Error: handler 
#3 never matches
         );
     }

This error is useful to have when you remove a member from your 
SumType, since it ensures you won't miss any code that needs 
updating. It also helps with introspection-based mapping, since 
it can catch cases where one function accidentally "shadows" 
another. `visit`, meanwhile, will let you pass it as much garbage 
as you want.

[1] https://dlang.org/phobos/std_variant.html#.visit
[2] https://pbackus.github.io/sumtype/sumtype.match.html


More information about the Digitalmars-d-announce mailing list