Erlang style - case vs function pattern matching

12,929

Solution 1

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...

Solution 2

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:

  1. They are represented in the same way in the VM so there is no difference in performance between the two solutions.

  2. 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.

Solution 3

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.

Share:
12,929

Related videos on Youtube

Alan Moore
Author by

Alan Moore

Chief Information Officer / Technology Officer of Incapture Technologies - creating a platform for distributed computing and application hosting in complex and fast moving environments.

Updated on August 29, 2020

Comments

  • Alan Moore
    Alan Moore over 3 years

    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.

  • Alan Moore
    Alan Moore almost 15 years
    The use of _ as a catch all clause always has a bad smell to me as well - I usually leave it out and let the pattern matching throw it out. But in this particular case I wanted to do nothing if it's not matching. I like the alternative approach of putting the guards in the case clauses...
  • Alan Moore
    Alan Moore almost 15 years
    Yes, I wrote the fragment from memory so the logic may be a little off. One of the things I liked about the first style was the magic construction of a tuple to do the pattern matching - I've used it before with something like {Test1, Test2, Test3, Test4} and then had a whole set of case clauses for the specific combinations I was actually interested in. It beat a whole set of nested if statements!
  • Gordon Guthrie
    Gordon Guthrie almost 15 years
    Worry about the cost of testing the size of a variable is micro-optimisation. Write the clearest possible code and, when you have an indication based on testing that this particular instance of this construction is too slow, then and only then change it.
  • Jeremy Wall
    Jeremy Wall almost 15 years
    I really like the function matching in most cases. Although the cycle for me usually goes something like: write case statement first. refactor into functions later. I tend to write the code as it comes then refactor heavily afterwards. The closer I can get it to one line functions the happier I am.

Related