Skip to content

Even simpler custom matchers #282

Closed
@tabatkins

Description

@tabatkins

I'm glad we added the new feature that the Symbol.matcher method can just be a boolean predicate for simplicity, but playing with some examples I don't think it's gone far enough.

If you have a boolean predicate in hand, the only way to invoke it within match is:

match(x) {
  when(${{[Symbol.matcher]: predFunc}}): ...;
}

(In this particular case you could instead write if(predFunc(x)), but if the value you're testing is arbitrarily deep in a pattern you can't easily do that; you'd have to bind the value with an ident matcher and then put the test in the following if(), which disconnects the two. Not ideal.)

It would be nice if we could write when(${predFunc}), and automatically infer that if predFunc is a function (and doesn't have a [Symbol.matcher] on it either), we should just call it with the matchable, treat the return value as a bool, and resolve it to the matchable as a pass-thru. (So you could use with on it as normal.) That is, treat it identically to the more verbose version above.

(Note Yulia's "Layer 1" in the alternate proposal https://github.com/codehag/pattern-matching-epic, which is just predicate functions. The syntax there doesn't work properly when you expand out to the full feature, but the use-case seems reasonable.)


If we did this, it's adding another carve-out to the fallback case (just === match) for non-primitives in ${} patterns - now, in addition to 1) objects with [Symbol.matcher] written by the author, 2) all the built-ins, and 3) every class, we add 4) every function to the list of "things that do something more complicated than just ===".

This is making me less sanguine about having that fallback case at all. We still want it for when the expression resolves to a primitive (for symmetry with the literal matchers, and just general usefulness), but I'm leaning towards non-primitives instead just throwing at runtime if they don't match one of the above cases. If you do want to equality-match against a non-primitive object, with this new functionality that's still pretty trivial - ${x=>x===someObj}. (And arguably this is clearer than ${someObj}, which looks like it's probably invoking a custom matcher rather than just using simple equality.)

This would also make it safer to add more cases in the future, like if we add enums or similar.

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions