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

Reply via email to