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 particula
The second is the preferred way especially if you can keep the clauses to a single line:
maybeCngStor(Sz, ets) when Sz > 10000 -> something;
maybeCngStor(Sz, dets) when Sz < 10000 -> somethingelse;
maybeCngStor(_,_) -> ignoreit.
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:
maybeCngStor(Sz, ets) when Sz > 10000 -> something;
maybeCngStor(Sz, dets) when Sz < 10000 -> somethingelse();
maybeCngStor(_,_) -> ignoreit.
somethingelse() ->
(...)
Return.
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:
#record{foo = F, bar = B, baz = Bz} = Parameter
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...
Learn you some Erlang for great good has a small section on when to choose case
and when to use a function
. 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.
case A > 10 of
true ->
case B > 10 of
true -> dummy1;
false -> dummy2
end;
false -> dummy3
end
would have to always execute B > 10 if you called it like
doTest(A > 10, B > 10)
when
doTest(true, true) -> dummy1;
doTest(true, false) -> dummy2;
doTest(false, _) -> dummy3.
which sometimes isn't what you want!
You can make these examples more similar by doing:
case Type of
ets when Size > 10000 -> ...;
dets when Size < 10000 -> ...;
_ -> ...
end.
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.
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.
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.