I've gathered that this will probably be an unpopular opinion as re-using switch/case has been mentioned, but I recently had a bit of a discussion on hacker news that pulled me towards this idea.
Namely, match is functionally equivalent to switch if both have pattern matching. I've gathered from the documentation here that this is a design intent and the idea is to have match replace switch entirely. While I'm on-board with some of the ideas proposed, I don't think adding a new language construct is entirely necessary.
For example, based on my understanding of the current proposal, these are roughly identical:
let foo = 'bar';
let ret;
switch(foo) {
case 'bar':
ret = 'baz';
break;
}
// --------------
let foo = 'bar';
let ret = match(foo) {
'bar' => 'baz'
}
But so, too, could these be roughly identical:
let foo = { bar: 'baz' };
let ret;
switch(foo) {
case { bar: baz }:
ret = baz;
break;
}
// --------------
let foo = { bar: 'baz' };
let ret = match(foo) {
{ bar: baz } => baz
}
I will grant that the match syntax is much terser and, in these contrived examples, just as, if not more easy to follow. However, I've found the overuse of arrow functions leads to a visual soup that is difficult to visually parse if not done well and that applies equally here (this is particularly true of the Redux reducer example in the readme).
Further, while I very much like the implicit return, this would be the only control construct I'm aware of (aside from ?:) that returns a value. In my opinion, this adds to the 'Wat?' factor of JavaScript more than upgrading switch would.
Lastly, I feel that upgrading switch in this way would actually make it more worth learning and using than the existing wimpy-if-statement-with-weird-semantics statement we have.
Some things this doesn't address are guards, match having no fall-through mechanism, and errors when nothing is matched. Guards, in particular, are useful and fall-through is a continual source of headaches. I don't really have an opinion on errors raised when nothing is matched; I could be convinced either way on that one.
Something like case { bar: baz } if baz == 'foo': would work for guards, even if I'm not a huge fan of the syntax.
Unless I'm horribly mistaken, these changes would be entirely backwards compatible and would make the switch statement actually useful for a broader category of problems.
case { bar: baz }: is the same as const foo = { bar: baz }; … case foo: - in other words, this is already valid syntax (albeit a case that could never have previously matched, since it's an inline object literal).
Getting far away from the massive anti-feature of default fall-thru is a sufficient reason to jettison switch into space and have a completely new construct, imo.
I understand the fallthrough hate, even though I’m a bit biased to see it as a feature due to its utility when parsing (fallthrough is still faster than Set.prototype.has in V8, and it seems unlikely that this will change). Because that utility doesn’t apply to higher level pattern matching at all, it’s left as a pure footgun, so I agree that adapting switch would only make things more confusing.
That said, I think I do feel where @chall8908 is coming from. This proposal is really exciting, but it’s also currently a bit of a soup — it seems to involve lots of novel constructs without precedent or symmetry with existing features. Is a minmax approach to match plausible? Does it need to cover every use case out of the gate or could it begin leaner and with a careful eye towards leaving the doors open?
I understand the fallthrough hate, even though I’m a bit biased to see it as a feature due to its utility when parsing (fallthrough is still faster than Set.prototype.has in V8, and it seems unlikely that this will change)
Fall-through is not a bad idea; it's just having it be the default behavior that's unfortunate. You can fall through in OCaml patterns though (keep in mind OCaml is statically typed and so fall-throughs are safe
@tabatkins I've heard this a few times, but I, honestly, don't understand the vitriolic hate over it. Sure, it's annoying, but not "literally burn everything" annoying...
I don't have vitriolic hate against switch. I just don't want to deal with the overlap in semantics. There are -at least- three major differences with switch that make me feel like this is important:
switch, which match lacks (and will not add), with the requirement to use break.match is an _expression_ and returns a value. In the current version, that value is the CompletionValue. This significantly changes the way clause bodies work.case:, using =>)If they were close enough constructs, we _could_ extend it, but I think the semantic augmentation here is important.
The case where I _would_ be ok with extending switch is if this proposal was _only_ adding new kinds of matches and literals to existing semantics:
switch (val) {
case {length}:
console.log(a)
case [b,c]:
console.log(a, b, c)
break
case 'foo':
break
default: idk
}
with all the associated "obvious" semantics that this would entail. To be honest, this seems like a reasonable possibility if the goal is to make the most minimal addition to the language, but loses out on a lot of functional benefits and leaves the break footgun in-place.
I've heard this a few times, but I, honestly, don't understand the vitriolic hate over it. Sure, it's annoying, but not "literally burn everything" annoying...
The 90% (at least) case for switch cases is to break immediately, no fallthru at all. Of the remaining cases, 90% of them use fallthru just to express multiple cases; that is, all but the last case in the chain has a totally empty body. Only a tiny, tiny minority of cases ever want to actually do something in a case, then fallthru to the next case, and yet that's precisely the default behavior.
This misfeature has caused untold numbers of bugs, and corresponding millions (likely, billions, all told) of dollars worth of losses as a result. All from a simple design mistake - it should have always broken by default, with a keyword that makes it fallthru instead.
@zkat I suppose my primary point of contention with this _is_ match being an expression. As I mentioned, there's only one other such construct and it doesn't even involve any keywords. IMO, this doesn't really improve the language much and I can easily see it increasing the confusion of new developers. If match is an expression, why isn't if or for or switch? At least the ternary operator is consistent across a number of languages (all the ones I know, anyway), so I'll give that one a pass.
I feel like you have a great feature (pattern matching) locked up in an attempt at killing off another language feature that, IMO, doesn't _need_ to die and could very much benefit from being updated/improved.
An anecdotal example, I just spent the last hour and a half trying to explain match to a co-worker and he still doesn't really get it. This is probably a combination of me being a bad teacher and him not really knowing JavaScript, but I couldn't even get the basic idea across! How is that going to translate to someone totally new to programming, let alone JavaScript?
switch is bad, I agree with you, but we're kinda stuck with it. It's not going to go away and it's _always_ going to be a footgun for the uninitiated. I would much rather it be a useful footgun than cruft we carry along telling people to ignore and not use.
FYI: C# also extended the switch implementation with pattern matching.
ref: https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching
Although, C# does need a special syntax to fall through if you are not expressing multiple cases. Still, just to give an example in a current language.
I think I'm gonna close this:
switch because it would be super confusing and fallthrough is awful as a default feature. It also has very different behavior with variables than this proposal expects in order to work.match is no longer an expression as of the latest version of this proposal, which addresses the other concern brought up here.A recent find I thought I'd share here: Java is extending its switch statements to become expressions, and pattern matching could be coming too.
I think this is meaningful in that it sets a precedent, not only in a an implementation extending "switch", but in developers who will learn different semantics for switch and could come to expect them in other languages too. Wether we want to jump in the bandwagon is up to us, but coming from the Ocaml world I was a big proponent for just ditching switch. This has made me re-consider extending switch; perhaps there's something to gain from their discussions and their approach.
Note: the syntax in the proposals seems different from the syntax in this article. I'm not sure what the final syntax will look like.
Note: the syntax in the proposals seems different from the syntax in this article. I'm not sure what the final syntax will look like.
The syntax appears to be the same to me, it's just that there are two syntaxes. They extended break to accept a value for the expression statement and added an optional expression form when you use -> instead of :, which is syntax sugar for the : statement form with an implied break <expression>;.
Most helpful comment
Getting far away from the massive anti-feature of default fall-thru is a sufficient reason to jettison
switchinto space and have a completely new construct, imo.