-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
matchable ~= pattern {…} #191
Comments
I think i see what you mean - a way to match a single pattern against a matchable. Would it throw when it doesn’t match? How would else syntax work? There’s already resistance from the committee about & and | being too similar to bitwise operations; ~ seems like it would fall into the same pushback? Separate from the answers to these questions, this sounds like a great follow on proposal to this one, rather than something that needs to be done immediately. |
No, I chose
An odd-numbered list of pattern/action pairs would have the last "dangling" pattern interpreted as an action instead: matchable =~ pattern1 { action1 } || pattern2 { action2 } || fallback;
// Example
var outcome = matchable =~ {foo: 1} 1 || {foo: 2} 2 || {foo: 3};
// The above is loosely equivalent to:
var outcome =
(matchable.hasOwnProperty("foo") && matchable.foo === 1) ? 1 :
(matchable.hasOwnProperty("foo") && matchable.foo === 2) ? 2 :
{foo: 3};
Nope, only resolve to // Example
var outcome = matchable =~ {foo: 1} 1 || {foo: 2} 2 || throw "No such foo"; This dovetails nicely with the "fallback" logic described above.
Truth be known, I only included those because feedback on #179 seems strongly in favour of |
Choosing anything with
This violates the priorities mentioned in the readme - matching should be exhaustive by default. |
Why? Unsuccessful matches allow nested patterns to be handled gracefully; i.e.: const subject = {foo: 1, bar: 0};
subject =~
{foo =~ [1 || 2]} && // Pass: expected 1 or 2, subject.foo is 1
{bar =~ 1} // Fail: expected 1, subject.bar is 0
{ … }; |
Because a match construct that doesn't match and doesn't throw is far more likely to be a bug that goes unnoticed than a match construct that doesn't match and does throw when that's intentional - ie, safety. |
There are plenty of cases where a benign match failure is desirable; e.g.: function makeVector(value){
if(value =~ [
x =~ typeof == "number",
y =~ typeof == "number",
x =~ typeof == "number",
]) return new Point3D(x, y, x);
else if(value =~ [
x =~ typeof == "number",
y =~ typeof == "number",
]) return new Point2D(x, y);
else if(value =~
({x =~ typeof number} || throw "Missing `x` property") &&
({y =~ typeof number} || throw "Missing `y` property")
}) return new Point2D(x, y);
else throw TypeError("Unable to resolve cartesian coordinates");
} Whether or not coverage needs to be airtight is a decision only the author can make. |
Sure - and that decision, per this proposal's priorities, must be explicitly present in the code - just like how |
The coverage requirement makes sense in Rust, which needs to consider all possible control paths (due to static compilation, etc). That's antipodal to a dynamic, high-level language like JavaScript. I mean, we could impose this requirement. But doing this reduces the operator's flexibility. Not to mention users will just stick a dummy branch so cases like the above example can work: if(value =~ [
// HACK: Fallback to `undefined` to avoid throwing an error
x =~ typeof == "number" || {undefined},
y =~ typeof == "number" || {undefined},
x =~ typeof == "number" || {undefined},
]) return new Point3D(x, y, x); |
The strict intention is to reduce flexibility, in order to increase correctness. It's totally fine if users want to stick |
In that case, there's no reason this can't be two separate syntaxes:
|
The current proposal is your number 2 there. The operator, as I said, is a great idea for a future proposal, dependent on the semantics established by this one, but I don't think it should be in scope of this proposal. |
Wouldn't it be more logical to resolve the pattern-matching semantics first? That's arguably the most important and compelling part. How exactly would this idea be proposed? |
Yes - that’s what the current proposal achieves. Then, proposing an operator to simplify a perhaps common inline use case becomes much more compelling. |
Well then, good luck. Hopefully the end result is sufficiently simple enough that the two ideas gel together. 😄 |
This is an interesting idea but yes maybe we won't do it now. But is it possible to join them into one? One branch mode: |
Actually, I'm wondering if "branches" should just be regular short-circuiting operators ( |
@Jack-Works i'm sure we could come up with grammar that was complementary - but that would still mean it could be easily added as a followon proposal. |
@Alhadis There's been a lot of delegate feedback that |
Fair enough. As long as the syntax is consistent and feels like a natural addition to JavaScript (instead of resembling Frankenstein's monster as if it were stitched together from the bodies of other programming languages…) 🐘 In any case, the OP has been updated to accommodate both outcomes (i.e., |
The champions group met today and reached consensus to not include this in the proposal. If there's sufficient interest, this can be implemented as a follow-on proposal, but it's out of scope for the base proposal. |
IMHO, this proposal might benefit from a simpler syntax, one modelled upon Perl/Ruby/Awk's
=~
/!~
operators:Pattern combinators would be accepted only at top-level; i.e.,
A limitation of this is that nested pattern combinators don't work:
Thanks to chainability, however, this does work:
Note this isn't an assignment operation, so logical operators have different precedence:
Patterns call
Symbol(matcher)
if defined, with successful matches indicated by an object with a{value}
property:If
|
/&
get rejected, then the suggested syntax can be simplified by using regular short-circuiting operators (??
/&&
/||
), subject to the language's usual grouping logic. This also eliminates the need to discriminate "top-level branches" from "nested" branches).Most of this was written on-the-fly, so there're probably some stupidly obvious oversights that my dumb arse managed to miss. Hopefully you get the idea… 😓
/cc @ljharb
The text was updated successfully, but these errors were encountered: