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?
While it's obviously safer and super helpful to have a compiler guarantee that there are checks for all cases, having a non-exhaustive pattern match call still be a big improvement over imperative checking of specific fields for control flow.
What I've seen doing fairly fast and loose prototyping and product iteration in Elixir over the last 2 years, is that patten matching can help create better boundaries and data guarantees within a codebase. A bug might still cause a runtime exception, but investigating and fixing the bug can be wayyyyy less painful than in JS, Ruby and friends when a nill/null/undefined/some-other-garbage can be passed very far through the stack before it eventually causes an issue.
Having a pattern match in the code, even a weak, non-typed pattern match on literals or basic data types, can act as an assertion in your code. "This is what the data needs to look like here if anything after is going to work". I think there is a probably an antipattern in taking this too far, coupling all sorts of your codebase to lower-level data structures There are better controls and safety mechanisms that can be implemented, but it can help a lot when there are specific parts of a codebase that are hotspots for issues, or where you're just trying to isolate where a data inconsistency is originating.
> Having a pattern match in the code, even a weak, non-typed pattern match on literals or basic data types, can act as an assertion in your code
Exactly. That's one of the key points I make when talking about Erlang: the = sign specifically, and pattern matching more broadly, are like having full-time, production assertions everywhere.
One key to the success of that in Erlang/Elixir, of course, is that you have the infrastructure and language support to manage widespread assertions that can fail.
And Prolog as well, which strongly influenced Erlang's design. (The original Erlang was written in Prolog.)
I agree with the sentiments of some of the other commenters -- it's much less troublesome to match on tuples (Erlang) and predicate clauses (Prolog) than it is to match on JavaScript objects. With tuples/clauses, the constructor syntax mirrors the pattern matching syntax, so it's trivial to read the code at a purely syntactic level to debug pattern matching issues, and this would simplify automatic static analysis as well. As soon as you can add "fields" to an object at arbitrary (non-local) points in the code, local syntactic analysis becomes intractable.
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:
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.)
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).
That is why I think we need some way to identify pattern matching + exhaustiveness checking, vs non-exhaustive switching matching is really more like "destructuring with syntactic sugar".
Exhaustiveness checking is what elevates pattern matching to the other side of the expression problem, which is about getting feedback from the compiler to help you write programs.
Hopefully this could be integrated with typescript as well, but this proposal would be great in certain cases to replace JS switch statements while also cleaning up the look of "case:" "break;" with something more elegant
What I've seen doing fairly fast and loose prototyping and product iteration in Elixir over the last 2 years, is that patten matching can help create better boundaries and data guarantees within a codebase. A bug might still cause a runtime exception, but investigating and fixing the bug can be wayyyyy less painful than in JS, Ruby and friends when a nill/null/undefined/some-other-garbage can be passed very far through the stack before it eventually causes an issue.
Having a pattern match in the code, even a weak, non-typed pattern match on literals or basic data types, can act as an assertion in your code. "This is what the data needs to look like here if anything after is going to work". I think there is a probably an antipattern in taking this too far, coupling all sorts of your codebase to lower-level data structures There are better controls and safety mechanisms that can be implemented, but it can help a lot when there are specific parts of a codebase that are hotspots for issues, or where you're just trying to isolate where a data inconsistency is originating.