-
Notifications
You must be signed in to change notification settings - Fork 89
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
Dropping when
keyword from match clauses?
#304
Comments
I'm not stuck on how |
I think readability/learnability is already completely handled by the fact that the only reasonable way to format a match is with each arm on a line. If someone does anything else, that's them shooting their own foot. We're not providing a footgun, they're just pointing downwards and pulling the trigger, and that's on them. It's the same as literally any other sequences of statements - if you're putting multiple statements on a line, you're either hurting yourself or you have a very good personal reason for formatting it that way. In all other cases, your match clause starts on a new line. You see a new line, it's a new match clause. For googleability, we already have the |
Given that the expression on the RHS will be multiline, and that's perfectly reasonable, I don't think this holds. |
It's an expression, tho. If it's multiline, you indent; that's how everyone writes their code already (or, again, they're just hurting themselves for no reason and we can't stop them). This is true if we have do-exprs too - the obvious formatting for do-exprs will indent their contents. Basically, do you think JS made a mistake in its general syntax, having statements not require an introductory keyword? Because that's the exact same situation, as far as I can tell. There's no difference between: if(...) {
statement;
statement;
long statement
.thatWraps();
statement;
} and match(...) {
pattern: expr;
pattern: expr;
pattern: long expr
.thatWraps();
pattern: expr;
} At least, as far I can tell. If you think there is a difference in these two cases, could you elaborate on that? Or if my reasoning is off-base at a different point? |
Those two cases are very different; the former is a series of top-down instructions, and the latter is a pattern to expression map. |
Am I remembering correctly that you'd object to respelling |
@rkirsling yes, but i'm open to almost any other respelling :-) I agree |
So what about a plain object, which would have the same structure lacking prefix keywords? I think it would be reasonable to mirror that considering it's also a map of sorts. |
@haltcase keying into a plain object is a map of sorts, sure - an object by itself isn't inherently like a match construct. |
Yes, I know they're different syntax constructs. My question is: for the purpose of reading, writing, and understanding code, how are they different? What makes the one acceptable without a prefix, while the other needs one? If you write So I'm asking you to elaborate on what, exactly, you feel is the problem being solved by requiring a prefix on arms, and why that same problem doesn't apply in other cases like this. |
I’m saying that they’re conceptually unrelated, despite syntactic similarity. I think that “what’s proper” is not an objective thing - it’s something the community discovers over time. Additionally, even long time practitioners of the language can have preferences that violate the community’s preferences. It’s not for us to deem whether separate lines is “proper”, that’s paternalistic - it’s certainly how I’d hope to write it. Our job is to design things that we think will be used and written best, and to ensure that other patterns either are impossible, or are minimally problematic. I personally believe that prefixes will help with readability, syntax highlighting, parsing, linting, googling/education/learnability, and, yes, starting each clause on its own line. |
I like the My concern is this example from the main document, when written without match (res) {
{ status: 200, let body, ...let rest }: handleData(body, rest);
{ const status, destination: let url } and if (300 <= status && status < 400):
handleRedirect(url);
{ status: 500 } and if (!this.hasRetried): do {
retry(req);
this.hasRetried = true;
};
default: throwSomething();
} This example is hard to parse visually, despite being formatted pretty well. I don't like that we have lines starting with braces for one thing, normally that would only happen inside of an object literal. Additionally, it feels really awkward for the colon separator to just sit between two things that kind of look like expressions or objects or... who knows what. It looks like ternary soup with missing question marks. Furthermore, there is no clear indication in the syntax that these lines are special, someone unfamiliar with this new syntax would likely expect that each line runs in order as statements would, not that it would terminate at one of them. Then there is the dangling The original exaple: match (res) {
when { status: 200, let body, ...let rest }: handleData(body, rest);
when { const status, destination: let url } and if (300 <= status && status < 400):
handleRedirect(url);
when { status: 500 } and if (!this.hasRetried): do {
retry(req);
this.hasRetried = true;
};
default: throwSomething();
} This is more clear, the Regarding match (subject) {
when { a }: ...;
if (condition == value): ...;
when { b }: ...;
} Basically, why not allow the lines to start with Though that brings up a question I'm having a hard time finding an answer to in the proposal: Why not just support boolean expressions in the patterns region? match (subject) {
when (value === somethingElse): ...;
when { has: "pattern" } and (value === anotherThing): ...;
} I assume I'm missing a reason why this can't be allowed? |
it would be confusing to conflate pattern space and JS expression space, imo. |
Yeah, patterns are a very distinct syntax from expressions, and can't be arbitrarily mixed. The one place we currently allow them (inside the
As far as I can tell, every problem you raise here except the first is exactly as present if you use As for the first, we do have lines starting with
Yes, you still write
Syntax special cases are generally a bad design. It means that, if you wanted to later edit that condition to add an |
I think you misunderstand half my issues with it. My point is that with the switch (<subject>) {
case <value1>: <expressions1>;
case <value2>: <expressions2>;
case <value3>: <expressions3>;
default: <defaultExpression>;
}
match (<subject>) {
when <pattern1>: <expressions1>;
when <pattern2>: <expressions2>;
when <pattern3>: <expressions3>;
default: <defaultExpression>;
} This results in something familiar, even if the shape of a pattern is complicated and confusing. Also, one could just as easily argue that switch should work like this: switch (<subject>) {
<value1>: <expressions1>;
<value2>: <expressions2>;
<value3>: <expressions3>;
default: <defaultExpression>;
} Is there really a reason why there must be a keyword
Yes, we have Typically I'm all for making things concise, but I think it goes a step too far here given how complicated the grammar already is. More signals to explain what's going on greatly benefit readability.
I'm not sure that I agree with this statement as a generality. Syntax special cases that lead to weird esoteric grammar aren't great, but special cases that work intuitively (as I would argue this one would) are generally beneficial. There's no reason that |
@zeel01 i was responding only to
The |
@ljharb I was only responding to @tabatkins. |
When we took over this proposal, we changed the original grammar of the
match
arms from<pattern> => <expr>;
towhen(<pattern>): <expr>;
, in part to allowif()
guards to be placed alongside thewhen()
, likewhen(...) if(...): <expr>
. We no longer haveif()
guards (rather,if()
is just a pattern syntax now), and so we removed the required parentheses fromwhen()
- the arms are now defined aswhen <pattern>: <expr>;
.I think the
when
keyword has become vestigial here, tho. There's no longer a grammatical requirement for it, and it makes some types of simple patterns, likewhen if(...): ...;
, read somewhat silly.Further, most languages with pattern-matching features don't have a per-clause introductory keyword (or other syntax) either: in particular, Rust, Haskell, and C# (in some cases) don't. (Python and Dart do, as does C# in some cases - they all happen to use
case
- so the ecosystem is mixed on the matter.)We should just drop the
when
keyword and make the syntax slightly lighter. This would resolve @rkirsling's objection aboutwhen if(...)
looking silly. However, @ljharb appears to have an objection to this, so let's discuss.The text was updated successfully, but these errors were encountered: