Description
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?