def f(pattern1) do
# ...
end
def f(pattern2) do
# ...
end
def f(pattern3) do
# ...
end
def f(pattern4) do
# ...
end
is much better than:
def f(x) do
case x do
pattern1 ->
# ...
pattern2 ->
# ...
pattern3 ->
# ...
pattern4 ->
# ...
end
end
The first version probably plays better with tracing, but that’s an artifact of how the tracer is implemented, and not a universal property of matching in function heads.
For what it’s worth, both versions emit exactly the same bytecode. At the core erlang level (one of the intermediate languages in the compiler right below Erlang AST) functions are lowered to a single big case inside one function and there are no more “multiple heads”.
Yes, and many people agree with you that multiple function heads are better. I was just trying to show that ot was very subjective and most benefit comes from pattern matching , whether in a case statement or in multiple function heads
There is also the proposal to add pattern matching to javascript.
I’ve always preferred the case statement pattern matching to the function head pattern matching - it’s much clearer to me. The community seems to have the opposite preference though, so I just go with the flow.
I am quite sure that the first is much better than the second. That’s why I would be frustrated.
I think the feature that is quite different between the two ( at least in Elixir) is variable scope. I know exactly where and when the variable is in scope vs having to keep in my head the languages internal rules about variable scope in complex logical structures.
In a language where = is an assignment operator, I’m not sure that pattern matching buys you all that much particularly in languages like Python and Ruby with their relatively complex variable scoping rules.
case/2 is a perfect fit for a small number of clauses each of which have tiny (one or two line) bodies - i.e. the resulting function isn’t going to be that large
if there are too many clauses, the function grows too large
if too many clauses have large bodies, the function grows too large
reorganizing a large case statement into multiple function clauses:
gives you the illusion of smaller functions (as it is actually one big function anyway)
while at the same time still having the relevant pattern colocated with the body
The biggest drawback is that there are instances where having all patterns tightly in one place is beneficial to
assess proper ordering
detect unintentional pattern overlap
detect unintentional pattern gaps
But even with case the patterns are spread all over the place if the clause bodies are large enough.
So it’s not that caseis worse - multi-clause functions are simply an opportunity to use a different style of code organization.
For me in OCaml/Bucklescript/ReasonML match/switch expressions often turn into a list of pattern -> function_invocation pairs.
Sounds like the age of code formatters could become a constant source of frustration…
Alo, author of Qo here and writer of massive issue comments on aforementioned bug.
I actually suggested something later in the thread that amounts to the multi-function clause for an individual match. I could very likely make it into a method creation / match as well with some ideas I came up with in Qo::Evil:
Basically compiling dynamic conditions into the most basic way to express the boolean statement possible (&& joins more or less) using binding.eval and injecting non-string-coercible types as local variables set on a hash during “compilation”.
Why? Because that runs at 10-20% off optimal vanilla ruby speeds in a lot of cases for sets of a decent size. Still experimenting on that one though.