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