I've got to the stage where I've written quite a bit of Erlang code now, and I can see some style (bad or good) creeping into the way I've been writing it. This particular idiom I'd like some opinion on - is it better (more readable/faster/whatever) to convert case style statements to function pattern matching?
E.g.
Compare (a contrived example)
case {Size > 100000, Type} of
{true, ets } ->
%% Do something to convert to dets
something;
{false, dets} ->
%% do something to convert to ets
somethingelse;
_ ->
ignoreit
end;
with
...
maybeChangeStorage(Size, Type)
...
maybeChangeStorage(Size, ets) when Size > 10000 ->
something;
maybeChangeStorage(Size, dets) when Size < 10000 ->
somethingelse;
maybeChangeStorage(_,_) ->
ignoreit.
I prefer the latter in most cases but I'd be interested in other opinion.
If in your function the first thing you do is open a case clause, it is better to convert this top level clause to function pattern matching.
The second is the preferred way especially if you can keep the clauses to a single line:
Makes it very easy to read and reason about. Always choose the style that will be easiest to read in the future. Often you find a set of clauses where one is a 10 liner and the rest are one lines only - break out the long one to a function:
Little things like laying out the clauses to align them and using short variable names matter - but don't fall into the trap of changing everything to P, Q, R.
A good trick if you use records a lot is to match out the records to short variables:
This gives you short variable names that make sense when you parachute into the function from 10,000 feet looking for a bug next Christmas. F obviously is a Foo, etc, etc...
You can make these examples more similar by doing:
This seems to be clearer to me. The advantage of splitting this to a separate function is that you get to give it a name which acts as documentation and appears in stack traces. If that snippet is part of a larger function I'd separate it out, otherwise it's okay as is.
One thing worth considering is that error case as written the function will accept Type arguments other than ets/dets. Unless this is really what you want it's worth making this clause more restrictive.
As for me first style is more clear and may be faster. But it need test to say it exactly. In second case if type!=ets then both "Size > 10000" and "Size < 10000" would be evaluated.
Learn you some Erlang for great good has a small section on when to choose
case
and when to use afunction
. Two things are mentioned:They are represented in the same way in the VM so there is no difference in performance between the two solutions.
If you need to use guards against more than one arguments, using a function may read better.
All in all, it is mostly a question of style and taste.
(Put as an answer to get the formatting of the code...!)
One thing I did find when I was making some changes is that this approach can alter default short circuiting. E.g.
would have to always execute B > 10 if you called it like
when
which sometimes isn't what you want!