
JavaScript Pattern Matching Proposal - JONBRWN
https://github.com/tc39/proposal-pattern-matching
======
genezeta
Leaving aside syntax preferences or other superficial concerns, I find it
discouraging that "Motivating Examples" for a proposal include direct
references to particular libraries, or particular libraries' examples.

I mean, that one (of two) motivations for _adding a feature to a language_ is
"Terser, more functional handling of Redux reducers", just feels wrong and
casual.

~~~
curun1r
It's probably more of a "know your audience" decision. Anyone who's used an
ML-derived language will understand the motivation for pattern matching. But a
large percentage of JS developers don't really have much background in non-
mainstream languages or programming language theory, so they chose an example
that's likely to resonate more with that group.

~~~
christophilus
> But a large percentage of JS developers don't really have much background in
> non-mainstream languages or programming language theory

Not to side-track the issue, but I keep hearing this. I'm wondering if this is
true, and if so, how such a statement is verified. I'm currently a full-time
JS dev, but have written my own programming languages, have professionally
written in C, C++, C#, F#, Ruby, and others, and have dabbled in many other
languages (and would _love_ to professionally work in Clojure). [EDIT: Er, to
the "non-mainstream" point, I've dabbled in Rust, Clojure, OCaml, Haskell,
PureScript, Erlang, Elixir, and Elm. I don't know many JS devs that have done
all of that, but most people I know have tinkered in odd non-mainstream
languages.]

Most JS devs I know are not single-language devs. Am I just a super anomalous
member of the JS community?

... Anyway, back on topic, I'm a big fan of pattern matching, so I'm all for
seeing this proposal become a reality.

~~~
chc
I think you're a super anomalous member of any programming language's
community. I doubt even one programmer in a thousand has written F#
professionally (not being hipster here — I haven't done it myself).

~~~
myrryr
a LOT of function programmers end up doing a lot of javascript work.

I don't think he is odd in any way.

~~~
wtallis
Sure, a lot of functional programmers probably do end up doing javascript
work. But that's still a large subset of a very small fraction of programmers
in general, and they're definitely still vastly outnumbered by the folks who
are barely more than script kiddies.

------
Tloewald
So the proposal is super confusing to me (but I hadn't seen match before). At
first I thought it had something to do with regex.

Essentially it's a switch variant that is (a) confusingly named 'match' (bad)
(b) returns a value (good?) (c) and is actually a kind of function (wha?),
since it (d) supports recursion, but (e) doesn't require break (good), (f)
looks like a bag of inline functions but isn't (bad).

How about provide a replacement for switch, with a name that isn't confusing
that doesn't require break but otherwise has switch semantics, isn't recursive
(we have a mechanism for that) and has the matching behavior suggested?
Assuming we stick with 'match' it would look like:

foo = match(x) { case {y: 1} : /* result if x.y === 1 */; ... }

Seems far less confusing.

~~~
aylmao
Love this comment; reminds me of what I thought when I first encountered
pattern matching.

a. Yup, that's what it's called in OCaml, Scala, F#, etc. Might be a little
confusing at first, but it's all about finding a "match" for your value, which
is different from a guard in an "if" or a "switch".

In an "if", you need to provide a boolean (or a value coercible to a boolean).
In a "switch" you don't provide the boolean, but under the hood the switch is
just iterating through and comparing your value to all cases: it computes the
boolean for you by testing if two values are equal.

Finding a "match" is different, because you're not comparing values, you're
also comparing structure. So for example you can do things like

match (v) { case { x, y: 3 } => ... case { y: 3, contents: { name: 'Foo',
error }} => ... case { x, y } => ... }

And it wont just compare "v" against all cases, do a deep comparison, check
the existance of certain keys and bind variables as necessary so you can use
them on `...`.

b. More so than "returning a value" I like to think of it as "resolves to a
value". Thinking of it as "returning" can be confusing since it might make it
sound too much like a function.

Switch/if are statements. They control flow, and ask the computer to do
something. Another statement is assignment; `var a = 0;` "does" something, but
it doesn't represent a value.

Expressions like `3 + 2 + x`, `f(x)/2`, and `match({x:3}) {...}` represent a
value that hasn't been computed, and then resolve to one.

c. This is why I prefer to think of it as an expression: cause expressions
resolve to values. Function calls are expressions too!

d. If you're in a function, all expressions support recursion since you can
mix them up. A

e. Awesome.

f. I think that's on purpose, because in a way each case acts a bit like a
funciton. You can define "arguments" in it that get bound to values, and they
resolve to another value.

~~~
Tloewald
I totally get what it does, even if I hadn't seen it before. What I don't get
is (a) the use of the word 'match' (that's unfamiliarity) and (b) the proposed
syntax which looks like an absolute mess, something worthy of PHP, and the
fact that we end up with something that isn't a function but is recursive. Or
something.

'x => x = 1' in Javascript, is an expression that resolves to a function. I do
understand the difference, and it's important.

'match(x) { {x} => foo }' is not a bag of functions but a new use of the '=>'
operator that is confusing/surprising. I can get over it, but why should I
have to?

'match(x) { {x} : foo }' would be less surprising.

You're saying 'match({x:1}) { ....}' is an expression, but is 'match(x) { {x}
=> foo }'?, What does it resolve to? It smells like it either isn't an
expression (just as you can't write x = switch(x) {...};) or it's a new kind
of function.

~~~
Sharlin
Apparently they're overloading the meaning of the => "fat arrow" in the
proposed syntax. I agree it's confusing because it's already used with lambdas
in case of JS, but many languages with pattern matching do use it (eg. Scala,
Rust). Other languages like Haskell and F# use the thin arrow -> instead.

Pattern matching can be _exhaustive_ or _non-exhaustive_. Basically, if a
match construct is going to be an expression it has to yield a value* for any
input value, ie. there has to be a case arm for every possible input. Usually
match blocks have a way to declare a "default" or "else" arm for those values
that don't match anything else. Some languages with static type systems can
statically figure out whether a given match expression is exhaustive or not.
But in JavaScript's case that's most likely not an option. The JS way is
probably yielding `undefined` if a value fails to match anything.

* or diverge, ie. loop forever, or exit via nonlocal means such as exceptions.

~~~
owl57
I believe all these languages, if they use some arrow in lambda syntax (so,
except Rust), use the same kind of arrow for pattern matching. It's an obvious
syntax choice when lambda arguments also use the same destructuring syntax:
why would anyone want to remember which of those is `[x,y]->x+y` and which is
`[x,y]=>x+y`?

~~~
Sharlin
Fair point, it does make sense.

------
bterlson
I think it's good to note that this proposal is not far along the process.
Pattern matching, if it clears TC39 (a tall order, to be honest), won't land
in a spec for half a decade at least I would bet.

So, keep the feedback coming, and don't worry that you'll have to learn this
syntax tomorrow. It's still very early, and I wouldn't be surprised if there
are at least a couple major revisions before anything like this lands in
ECMAScript.

~~~
gedy
With babel plugins/transforms this could be used a lot sooner than that

~~~
bterlson
Babel has a lot of plugins, and hopefully people don't have to learn all of
them. How many people use stage-0 plugins for bind operator or do expressions?

You're right that Babel (and TypeScript!) implement features earlier than they
land in the spec, but at least TS does so only when it's almost for sure going
to make it in (around stage 3) and people probably shouldn't be using stage
0-2 plugins for anything but experiments, IMO.

------
cshepp
Pattern matching would be a great addition to JS. I built a pattern matching
library[1] with a very similar syntax back in 2015 (although I will be the
first to admit that it's a naive implementation). It makes
validating/traversing deeply-nested objects much less verbose. I'm excited to
see where this proposal goes.

[1] [https://github.com/cshepp/Kasai](https://github.com/cshepp/Kasai)

~~~
mpfundstein
Shameless plug but here is my pattern machter [1] :D

Example:

    
    
        // simple factorial
        const factorial = n => match(n)
            .when(0, 1)
            .otherwise(n => n * factorial(n - 1));
    
        // walking a tree
        class Tree {
            constructor(left, right) {
                    this.left = left;
                    this.right = right;
            }
        }
    
        class Node {
            constructor(value) {
                    this.value = value;
            }
        }
    
        const T = (l, r) => new Tree(l, r);
        const N = v => new Node(v);
    
        const walkT = t => match(t)
            .when(Node, v => console.log(v.value))
            .when(Tree, t => { walkT(t.left); walkT(t.right)})
            .otherwise(_ => 'error');
    
        const mapT = (f, t) => match(t)
            .when(Node, v => N(f(v.value)))
            .when(Tree, t => T(mapT(f, t.left), mapT(f, t.right)))
            .otherwise(_ => { throw new Error('error') });
    

Works also on deeply nested objects.

[1] [https://github.com/MarkusPfundstein/pmatch-
js](https://github.com/MarkusPfundstein/pmatch-js)

~~~
cshepp
Method-based syntax for pattern matching is easier to read and grok (IMO), but
it lacks the dynamic capabilities of data-oriented syntax (in Kasai, patterns
can be built/manipulated at runtime). It's interesting to compare the two
approaches.

~~~
mpfundstein
If you mean by method-based pattern matching that you evaluate a function for
each 'case'. My lib can do that do:

    
    
        const match = require('pmatch-js')
        const _ = require('lodash')
    
        const fizzbuzz = x => match(x)
          .when(a => a % 3 == 0 && a % 5 == 0, 'fizzbuzz')
          .when(a => a % 5 == 0, 'buzz')
          .when(a => a % 3 == 0, 'fizz')
          .otherwise(a => a)
    
        console.log(
          _.range(1, 101).map(fizzbuzz).join(' ')
        )
    

But maybe you mean something totally different :-)

EDIT: Ah I think I know what you mean. Your lib takes an array of tuples to
define the patterns. Sorry for the confusion.

~~~
dkarbayev
Wow, importing the whole lodash to use just one function? There’s es6 way of
getting an array with a range of numbers:

    
    
        [...Array(100).keys()].map(v=>v+1)
    

A little bit longer but no dependencies.

~~~
fangaorne
Although this method is pretty, I see 4 loops in this small line. a better way
would be to only import the range method from lodash like so :

    
    
        import _range from "lodash/range";

------
sakuronto
Interestingly, the match construct is an expression, which I don't think
JavaScript has m/any of. Perhaps they could retroactively make if/else
expressions, if that doesn't break back-compat.

~~~
cevn
That would be really cool. This match feels a lot like Rust's which is good.

~~~
c0nfused
I would argue that it doesn't feel like JavaScript much which seems bad.

~~~
kristiandupont
Why? To me it seems pretty aligned with the "feel" of destructuring.

~~~
c0nfused
In my mind there are several valid options out there now:

1\. Regex style: new match(input, options);

or built in function match(foo, bar);

or like switch match (foo){ cases

}

But, to have the switch statement syntax and return a value seems like a less
than good way to implement this.

------
bastawhiz
I can only see this being a foot gun. Deep equality testing of objects is
going to encourage the use of getters. Getters with side effects (no way to
prevent them) will basically ruin your day if you try to use pattern matching
with them.

Additionally, this would be the first "native" way to do deep equality testing
of objects. I can see it being abused to do simple one-off checks that could
otherwise have been done more simply in an imperative way.

Do we really need to save the five lines of code at the cost of new syntax?
This doesn't seem to prevent any significant amount of toil, since it can be
pretty easily unrolled into existing JS syntax.

~~~
heretoo
If it is five lines of code vs. one line of code, and we believe that the
number of bugs is proportional to the number of lines of code, irrespective of
which language we are programming in, then this would be an obvious benefit.

And it isn't four lines saved, but four lines times the number of uses in the
entire code base.

~~~
XR0CSWV3h3kZWg
> we believe that the number of bugs is proportional to the number of lines of
> code

Why would you believe that?

And if you do believe that why don't you use a code golfing language?

~~~
always_good
What exactly are you contributing by taking what they said to the extreme?

Should someone now have to point out to you that a million-line function is
worse than a ten-line function for calculating fizzbuzz? Is that meaningful
discourse in your book?

~~~
XR0CSWV3h3kZWg
My response seems to have upset you. I'm sorry that happened.

In general I believe that number of lines of code is correlated with number of
bugs, but I would hesitate to say that it is proportional to. Going in with
the explicit goal of reducing the number of lines could easily lead to more
bugs, not less.

------
lolive
Isn't pattern matching interesting only in a strongly typed environment where
the compiler can statically check that you are giving instructions for all
possible cases?

~~~
lmm
No, not at all. E.g. Erlang is built around pattern matching as a core feature
even though it's an untyped language.

~~~
jerf
Erlang was built from the ground-up with pattern matching in mind, so it
works. Instead objects are jammed into the pattern matching system, and where
the two disagreed, pattern matching won. (Indeed, Erlang doesn't really even
have objects, just some object-like convention.)

In a language that started with an object model that has grown a lot of
features, trying to jam pattern matching into it after the fact grows a lot of
corner cases fast. For instance, consider:

    
    
        a = {x: 1}
        a.toString = function() { return "magic: " + this.x }
    

Should a pattern match with the string "magic: 1"? Well... probably, because
it turns out that "magic: 1" == a is true. But if we do that, how does the
pattern match tell a is not in fact a string, if we want to do that? You can
answer that question, but the answer will raise further complications of its
own. Or you could build a pattern match system around ===, which will raise
its own issues. And goodness help the pattern matching syntax if it decides
that both are too useful to ignore (a defensible position) and now the syntax
needs to support both....

I'd say this proposal is about 10 times too short to be useful, and by the
time it's long enough to be useful, it'll be clear that almost nobody will
want to learn how to take the already sloppy Javascript equality situation and
then learn how to lay down a pattern matching language on top of that.

By contrast, since Erlang was built on pattern matching from day one, = and ==
have almost no such questions about them. It is very clear what they do. I did
have to check what 1 == 1.0 was, even after years of use of Erlang, since I
never used floating points in Erlang to speak of. (It is true, which
technically I find a bit weird. I'm not sure there's another example of values
of different types that can be equal. Note "" == [] because double-quotes are
defined as producing lists and strings aren't actually a type, so that's not
an exception.)

~~~
tannhaeuser
I believe Erlang inherited its pattern matching from Prolog term unification
since Erlang was prototyped as a DSL using Prolog's _op_ built-in predicate
(plus other Prolog parsing DSLs such as definite clause grammars).

[1]: [http://www.swi-prolog.org/pldoc/man?predicate=op%2f3](http://www.swi-
prolog.org/pldoc/man?predicate=op%2f3)

~~~
jerf
Heh, OK, Erlang was built for pattern matching from... uhh... the water table
up? The mantle up? :)

------
m0meni
Pattern matching seems to be very trendy/popular right now. It's a big jump
from JS, but [https://reasonml.github.io](https://reasonml.github.io) has very
nice pattern matching that you can use, and it integrates with the JS
ecosystem very nicely.

~~~
adamnemecek
It's been "trendy" since the 70's. It's more that more people have experience
with it and realize that pattern matching is like conditional statements on
steroids.

~~~
lmm
> It's been "trendy" since the 70's.

It's been possible since the '70s but I've seen a lot more talking about it in
the last 5-10 years.

~~~
stiGGG
Yeah, this applies to all that old Lisp features.

~~~
masklinn
AFAIK pattern-matching is not a historical Lisp feature, it's usually been
limited to simple destructuring.

In the modern acception of tree patterns (as opposed to text patterns aka
regular expressions), I guess it comes from ML (and possibly prolog but
prolog's unification goes even further?): it doesn't look like ISWIM had tree
patterns and I can't find older references.

~~~
lispm
In Lisp pattern-based programming has been first implemented in 1962 in by
D.Bobrow (METEOR). From then on there are many implementations of pattern
matching in Lisp based software, from Planner, to rule-based systems, LISP70
(Tesler, ...)...

~~~
Roboprog
This makes me sad. As somebody who started a CS degree back in the early 80s
(finishing in the late 80s), and who had a few glimpses of languages which
didn’t suck, the switch down to “everything is an 8086 running C code, if not
x86 assembler” was an incredibly destructive event in this industry.

I was going to specialize in AI in my major, but I guess it was about 25 years
too early. But that’s another tangent.

------
lgessler
Looking at this as someone who's been writing a lot of ClojureScript lately,
I'm reminded of how nice it is to be writing in a Lisp: if I felt this was the
right syntactic construct for a common-enough problem in my codebase, I'd
write a macro for it and get on with my life without having to wait for it to
trickle through committees, compilers, and browser implementations.

~~~
WaxProlix
And the next person to maintain your codebase would be grateful for your
choice and insight, I'm sure.

Permissiveness is good for small projects but it can feel like getting into a
suit tailored specifically for everyone else as projects get bigger.

~~~
jwr
I don't think this snarky remark is warranted. I think the point was that in
Lisp-style languages (such as Clojure/ClojureScript) new features such as
pattern matching can easily be added without "changing the language", as
libraries. This is how core.async was added to Clojure, to pick a non-trivial
example. Or more to the point, how core.match works.

Additions such as those do not have to be one lonely programmer's macros, they
can be libraries widely accepted by the community.

I had a similar thought when reading the ECMAscript extension proposal: I'm
glad that in the languages I use, features like that can be provided by
libraries.

~~~
emodendroket
Yes, but I think the other point is well-made, as well: languages that allow
this can be very difficult to work in if you have to maintain a large app with
multiple contributors over a long period of time.

~~~
heretoo
The same can be said for function calls, with the indirection they create
hiding details of broken and side-effecting implementations.

None the less, the opposite is also true. Languages that have macro facilities
can aid in writing more legible code. (See `threading` in clojure), or the
`loop` macro and regular expression macros in common lisp.

~~~
Roboprog
Well said. Rambling Java code with little to no abstraction is its own kind of
nightmare.

Some people are just terrified of any new abstractions, I guess, preferring to
work with an endless series of tally marks, rather than these obfuscating
“multiplication” and “exponent” complications (exaggerating to make a point -
abstract != unintelligible).

~~~
emodendroket
I think there is probably some middle ground between "no abstraction at all"
and "literally anything goes."

~~~
Roboprog
LCD?

Alas, that tends to be the steady state for Enterprise development :-(

(I know that’s not literally what you said, but that’s where that “middle
ground” attitude leads to: the bottom)

------
simonw
I really like this. The syntax looks a little weird at first, but it's
actually a very nice complement to modern JavaScript's object destructing
mechanism: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)

------
c0nfused
Its an interesting concept but, The choice of syntax seems bad.

The definition bit looks like a function definition but behaves entirely
differently. Why? Why not make it a constructor like everything else? People
could look at it and be like "oh a match object" instead of wondering if you
overloaded function.

The selectors look like json, only assignable. Again make it obvious.I mean we
could even just make it json why not.

~~~
irrational
I made the same type of arguments about fat arrows but everyone told me to
stop whining and I'd get used to it. Years later fat arrows still feel like a
bad syntax choice.

~~~
dvlsg
Really? I quite like them. I did get used to them in C# first, though. What
would you have preferred?

~~~
irrational
I would have preferred a word.

const my_arrow_function = arrow_function(){}

arrow_function my_arrow_function(){}

arrow_function(){}

~~~
warty
In older C#, that would be delegate:

    
    
        delegate(int x){ return 10; }
    

(But yeah, nowadays that would be:)

    
    
        (int x) => 10

------
frou_dh
You know that quip about C++ being an octopus made by nailing extra legs onto
a dog?

Is the same phenomenon somehow tasteful when it comes to ECMAScript {({...,
sy: nt => ax, ...}({,})} ?

~~~
GlennS
I feel like JavaScript is already a sort of functional language, so going in
this direction is ok.

It's the object/class additions where I think it's all going a bit C++.

Start with prototypical inheritance, but with a Java-style `new` keyword that
makes everything confusing. Next bolt on classes on the one hand, while
correcting your prototype system `Object.create` on the other.

R has 3 different object systems and none of them are any good. How long
before JavaScript catches up?

~~~
sjellis
I think that one of the reasons that classes were added to the language was
that people kept implementing them anyway, so it was better to standardise.
This may be a good thing: JavaScript arguably has to be multi-paradigm, more
than other languages, because the user-base is so diverse.

------
rattray
Surprised nobody has mentioned zkat's "fork", which contains a lot more
detail:

[https://github.com/zkat/proposal-pattern-
matching](https://github.com/zkat/proposal-pattern-matching)

zkat (who is also an npm employee) is a leading committer to the tc39 version,
so I think there's some chance that many aspects their version will be adopted
into the proposal.

------
xodeus
If I do the following:

    
    
      let visFilter = 'foo';
      const newState = match (action) {
        {type: 'set-visibility-filter', filter: visFilter} => console.log(visFilter)
      }
    

What happens?

Is it checking if action.type === 'set-visibility-filter' && action.filter ===
'foo' or is it destructuring the value of action.filter into visFilter?

~~~
always_good
Every example in on the readme demonstrates that using an identifier in that
position becomes destructured assignment.

~~~
xodeus
found the answer in the full proposal. Variables will always be assigned to,
never checked for equality.

To me this is pretty average and seems like it will cause magic
numbers/strings/etc if I can't use constants where it makes sense. The
proposed solution is to do something like

    
    
      { status: 200 } if (x === foo) => // do something
    

which just seems (for this type of use case, maybe not all) like more
boilerplate code for no real benefit over just doing something like

    
    
      if (res.status === 200 && res.x === foo) //do something
    

I would much prefer if there was some sort of special operator used to either
check equality or to destructure when matching so it is obvious what the code
is doing.

------
d--b
Javascript is such a mess, this proposal looks really bad, and the guys
discussing it are saying things like: "we should make sure that this doesn't
look like anything else, so that people who learn the language don't confuse
match and switch..."

There is also a lot of "we shouldn't break that" messages, and people reply
with "oh we already screwed that up here and there, so it's fine"...

~~~
Dibes
as someone who only has a little experience with pattern matching, how does
this look bad? The syntax looks good enough to me that I could and would want
to use it.

~~~
ealhad
“looking bad” is a really subjective thing.

Here is the syntax for different languages:

\- Rust [https://doc.rust-lang.org/stable/book/second-
edition/ch06-02...](https://doc.rust-lang.org/stable/book/second-
edition/ch06-02-match.html)

\- Haskell [http://learnyouahaskell.com/syntax-in-
functions](http://learnyouahaskell.com/syntax-in-functions)

\- Scala [https://docs.scala-lang.org/tour/pattern-
matching.html](https://docs.scala-lang.org/tour/pattern-matching.html)

------
techsin101
I just want to have ? Functionality in js like Ruby...

So I can do

let name = obj?.data[i]?.name;

And not get error can't read property data of undefined, when there is
something wrong, just have undefined as value.

To fix this I've to write redudant checks for each level of nested property.
Or do stuff like (obj || {}).prop....

------
LOLCAT1024
This proposal will increase code coupleing by fixing the object structure,
this will lead to refactoring problems and so on. A better approach would
allow to match objects by their fileds while leaving the structure of the
object unspecified.

~~~
edflsafoiewq
Can you elaborate? What do you mean "match objects by their fields"? How does
the proposal not already do that?

~~~
LOLCAT1024
Maybe I did not express my self correctly, what I meant was - in it's current
state the proposal rquires, when matching against an object, to specify all
it's fileds, say you have an object with keys a, b, c then even if you match
soley against the values of a , b you are required to specify c and by doing
so notify it's existence. This poses a problem , since if you now remove c or
add a filed d then the match will break failing to the default case , this
means failing silently the worst that can happen. The described situation will
be more then common since objects are ubiquitous to modern day js. Sadly
nobody noted the existence of such a design flaw , which in my opinion is
rather big since the proposal in it's current state implicitly turns objects
into some kind of types , which they are not, such transformation will result
only in increased coe coupleing , since anyone who matches against an object
basically specifies it's type and as a consequence only doom and despare will
follow to anyone involved.

~~~
edflsafoiewq
> in it's current state the proposal rquires, when matching against an object,
> to specify all it's fileds, say you have an object with keys a, b, c then
> even if you match soley against the values of a , b you are required to
> specify c and by doing so notify it's existence

I think this is wrong. The proposal says that a pattern like `{x}` matches if
the object supports `ToObject` and if its `x` property is not undefined. It
doesn't say anything about requiring that the object have no other own-
properties. This is consistent with how destructuring already works in JS (it
ignores any extra properties).

------
bcheung
I'm wondering whether types would be required to implement static analysis to
see if a particular scenario in the match is not handled. Haskell has the
ability to generate a compile error if you don't have a match specified for
each possible permutation. This makes it easy to make sure you handle all
possible inputs. This probably wouldn't be possible in JS. Probably the best
that could be done would be if the default matcher was left off.

~~~
emodendroket
The example seems to be a dictionary, so of course you cannot guarantee that
all possible permutations are covered.

------
mattbierner
I would prefer `match { ... } (value)`, with the `match` keyword essentially
creating a function that does the matching when it invoked. Minor seeming
change, but then you can think of match as being a generalization of arrow
functions instead of a special new language construct (i.e., `(...args) =>
...` is just shorthand for `match { ...args => ... }`)

I can understand why though they went with similar syntax to a switch
statement though

~~~
edflsafoiewq
This wouldn't work if the match contained eg. break or return.

~~~
mattbierner
Yes, if match is an expression than this restriction is the correct design in
my opinion

------
chunkyslink
Could someone please explain what this could be used for ?

~~~
soccergee
Smooshes the evaluation of an object that can be many different shapes into an
easy to understand operation.

I think the HTTP response is a great example. It can have many status codes
which can determine how you want to proceed with that response. If you've
worked with handling HTTP responses, you've most likely implemented some
version of a 'match' operation before.

~~~
codedokode
Is not `switch` enough for this?

~~~
cevn
It's more concise than switch, as well as more powerful (can destructure
objects). You can't set things equal to the result of a switch. I find the
pattern very convenient.

    
    
      let day;
      switch (date) {
          case 1:
              day = "mon";
              break;
          case 2:
              day = "tues";
              break;
          default:
              day = "wed";
              break;
    

vs

    
    
      let day = match(date) {
          1 => 'mon',
          2 => 'tues'
      }

~~~
Zyst
In fairness I think that would look a bit more like this:

    
    
        const getDate = (date) => {
          switch (date) {
            case 1:
              return 'mon'
    
            case 2:
              return 'tues'
    
            default:
              return 'wed'
          }
        }
    
        let date = getDate(1)
    

Which is, of course, still less terse. What I normally use when I have cases
like this is an object-as-a-map. IE:

    
    
        const dates = {
          1: 'mon',
          2: 'tues'
        }
    
        let day = dates[3] || 'wed';

~~~
codedokode
By the way, I don't think it is a good idea to write a function as a constant.
Please compare this

    
    
        function getDate(date) { .. } 
    

to this:

    
    
        const getDate = (date) => { ... } 
    

The first version is more readable. We instantly see that it is a function and
in a second case it looks like a constant at first. Also without the equal and
arrow sign it looks simpler.

~~~
Prefinem
Life is more fun with fat arrows sometimes

    
    
        new Promise(function (resolve, reject) {
            methodOne(data, function (error, response) {
                if (erorr) {
                    reject(error);
                } else {
                    resolve(response);
                }
            })
        })
    

vs

    
    
        new Promise((resolve, reject) => methodOne(data, (error, response) => error ? reject(error) : resolve(response)));

~~~
goatlover
That one liner has a lot going on. The first one is easier to read.

~~~
codedokode
Please also look at my idea how to rewrite the code for readability using
`deferred` pattern:
[https://news.ycombinator.com/item?id=16933983](https://news.ycombinator.com/item?id=16933983)

------
mattferderer
I would imagine you could do typeof === "string" or instanceof Foo to add JS's
limited type support? Elixir is similar in that it's not a typed language but
can allow limited types like this.

I personally wish the syntax was similar to overloading functions in other
languages, but I doubt that's possible due to the way destructuring & default
values were implemented.

------
_sdegutis
I'm not familiar with the JS proposal process. Is this likely to become an
official feature now that it's been proposed? If so what's the usual timeline
of that look like? I would love to have this feature ASAP in the browser
and/or Node.js and am eager to find out when that will be possible.

~~~
simlevesque
Someone will surely do a Babel plugin to use the syntax allowing you to try it
before it becomes an official feature.

~~~
Already__Taken
It's at the bottom of the proposal
[https://github.com/babel/babel/pull/7633](https://github.com/babel/babel/pull/7633)

------
jiaweihli
I love pattern matching, but find libraries with sugar or unintuitive APIs
hard to navigate. I built Rematch[1], which I hope avoids those two issues.

[1]
[https://github.com/jiaweihli/rematch](https://github.com/jiaweihli/rematch)

------
SilasX
Is that really the most pressing problem with Javascript? The lack of one more
way of expressing a common pattern? Not, say, the lack of typing or ease of
code obfuscation or unintuitive type comparisons the lack of a standard
library or ...?

------
codedokode
What an ugly syntax. They should follow switch/case syntax for consistency.

~~~
Analemma_
Pattern matching doesn't work the same way as switch/case though. Using that
syntax would be misleading and confusing.

~~~
maemilius
I think there's an argument to be made that switch statements already do
something adjacent to pattern matching. At the least, it's close enough that
something like:

    
    
      switch(expr) {
        case 'foo':
          break;
       case { foo: bar }:
          break;
      }
    

Wouldn't strike me as all that strange. It just shifts the semantics from "are
you exactly this" to "do you look like this". For non-object primitives (e.g.
string or number), I don't think those two things are functionally different.

Granted, it doesn't help make switch any easier to learn, but I _do_ think it
makes switch more _rewarding_ to learn. Right now, switch is basically just a
restrictive, potentially terser version of an if statement. This would make
switch actually useful to learn.

It might even allow us to add some more semantics to switch over time (e.g.
constructor matching with something like 'case Number').

(EDIT: thanks to armandososa for teaching me a new thing!)

~~~
armandososa
You'll need to insert a newline and 2 spaces before a code block to be
recognized as such:

    
    
        switch(expr) {
           case 'foo': break;
           case { foo: bar }: break; 
        }
    

[https://news.ycombinator.com/formatdoc](https://news.ycombinator.com/formatdoc)

~~~
maemilius
Ah, thanks. I should have guessed it would work something like that.

------
sergiotapia
I wonder if they can make it behave like Elixir's pattern matching. Multiple
functions with different params, same name.

~~~
lightbyte
Elixir's multiple function heads are just syntax sugar for a case statement.

------
fauigerzigerk
This reads very much like an ideology first, evidence second piece.

How on earth is it bizarre to make neighborhood roads worse to drive on for
commuter traffic? And defunding public transport?

You can have a debate about these things, but calling it bizarre betrays the
sort of "reasoning" that is dominated by an ideological anti public-anything
bias.

------
bcheung
I'd like to see how this would handle nested matching in the examples.

------
mgoetzke
are the `=>` actual hidden functions with own scope or are they syntactic
sugar? If they are functions they wont have a name in stack traces and add
overhead.

------
devmunchies
are there any 10+ year old languages that are "advancing" as quickly as JS?
Ruby? Python? C++?

Why Not?

~~~
mattbessey
I love where JS is heading, but perhaps its worth pointing out its a lot
easier to rapidly advance a language that historically has been missing huge
features.

~~~
aylmao
I'd also argue none are as important as JS. People can choose to not use Ruby,
Python or C++, but if you're doing web atm you're pretty much stuck with
JavaScript.

------
JONBRWN
I should note, this isn't my proposal. Just found it interesting enough to
share

~~~
soccergee
Thanks for sharing.

------
ihsw2
For those looking to digest more information on pattern matching in the JS
world, there has been an open proposal for TypeScript to support pattern
matching of some flavor.

[https://github.com/Microsoft/TypeScript/issues/165](https://github.com/Microsoft/TypeScript/issues/165)

------
googlemike
Out of the major, popular languages today, Javascript is easily the worst.

~~~
pitaj
Flame bait on HN is discouraged and could eventually get you banned.

------
z3t4
Stop using (nested) ternary operator's ! Use if-statements!

    
    
      if(val==1) var res = 1;
      if(val==2) var res = 2;

~~~
Epenthesis
Except ternary expressions have the _huge_ advantage that they allow assigning
to _const_. Eg:

    
    
        const var =
          val == 1 ? 1 :
          va1 == 2 ? 2 :
          null;

~~~
z3t4
It's hard to argue about not using const, but can you remember any time where
const actually prevented a bug !?

