[erlang-questions] case expression scope

Szoboszlay Dániel dszoboszlay@REDACTED
Tue Mar 4 23:41:19 CET 2014


On Tue, 04 Mar 2014 22:49:12 +0100, Richard A. O'Keefe <ok@REDACTED>  
wrote:

> No, you are still thinking in C/C++ terms.
> There are three  things in Erlang that are scopes:
> 	- a function clause is a scope
> 	- a 'fun' is a scope
> 	- a list comprehension is a scope

Personally, I feel that these rules are neither convenient nor intuitive.  
Mainly due to the last one, about the list comprehensions. I *know* that  
list comprehensions are implemented with funs, hence the scoping, but it  
still *looks like* a big exception from the "one function, one scope"  
rule. And if you have background in any C-descendant language you would  
almost certainly feel that cases, ifs, trys, begins etc. shall have their  
own scopes too.

Some examples where I really miss them:

foo(Dict) ->
     Value = case orddict:find(foo, Dict) of
                 {ok, Value} -> Value;
                 error       -> calculate_very_expensive_default_value()
             end,
     ...

Sorry, variable 'Value' is unsafe in 'case', please rename your internal  
variable to 'Value1' or refactor this humble four-liner into a  
get_foo_from_orddict/1 function, whichever you feel more inconvenient.

And we aren't done yet, let's add my favorite, the error-handling mess-up  
to the mix!

foo() ->
     ...
     V1 = case bar() of
              {ok, Bar} ->
                  Bar;
              {error, Reason} ->
                  lager:error("SOS ~p", [Reason]),
                  BarDefault
          end,
     V2 = case baz() of
              {ok, Baz} ->
                  Baz;
              {error, Reason} ->
                  lager:error("SOS ~p", [Reason]),
                  BazDefault
          end,
     ...

Of course I know real programmers never put two cases in the same  
function, but lazy people tend to. And lazy people also tend to use  
convenient variable names like Reason or Error in error branches. And than  
get compile errors or random badmatch crashes, depending on their code's  
complexity.

The only benefit I see of *not starting* a new scope within a case is that  
you can do this:

foo() ->
     case bar() of
         1 -> X = 1;
         2 -> X = 2;
         _ -> X = 0
     end,
     bar(X).

Which, in my opinion, is less readable than:

foo() ->
     X = case bar() of
             1 -> 1;
             2 -> 2;
             _ -> 0
          end,
     bar(X).

I hope these examples may pass the "this code is too trivial/ugly to even  
notice your actual problem" filter with better luck than the previous  
nominee. :)

Cheers,
Daniel



More information about the erlang-questions mailing list