Erlang Central

Difference between revisions of "Nested Cases"

From ErlangCentral Wiki

Line 1: Line 1:
[[Category:Best Practises]]
+
[[Category:Best Practices]]
 
This article describes one of the Erlang best practices. It is particularly difficult to trace errors when a programmer used many nested case statements in a single function.
 
This article describes one of the Erlang best practices. It is particularly difficult to trace errors when a programmer used many nested case statements in a single function.
  

Revision as of 08:40, 2 September 2006

This article describes one of the Erlang best practices. It is particularly difficult to trace errors when a programmer used many nested case statements in a single function.

Consider the following code fragment that implements a basic operation table:

  1: function(Operation,Values) ->
  2:   case Operation of
  3:     null -> 
  4:       null;
  5:     multiply -> 
  6:       case Values of 
  7:         [A,B] when integer(A), 
  8: 	               integer(B) -> 
  9: 	      {ok,A*B}
10:       end
11:     end.

As you can see, it contains a nested case (line 6).If we execute the multiplication operation, the code performs as expected:

(rvg@davinci)5> test:function(multiply,[5,2]).
{ok,10} 

Now, let us try an invalid operation:

(rvg@davinci)6> test:function(divide,[5,2]).

=ERROR REPORT==== 25-Dec-2004::20:30:28 ===
Error in process <0.43.0> on node 'rvg@davinci' with exit value: 
{{case_clause,divide},[{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {{case_clause,divide},
            [{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]} **

As expected, the shell crashed with a case_clause. Now, let us try the same with invalid multiplication parameters:

(rvg@davinci)7> test:function(multiply,[5,2,3]).

=ERROR REPORT==== 25-Dec-2004::20:33:05 ===
Error in process <0.47.0> on node 'rvg@davinci' with exit value:
 {{case_clause,[5,2,3]},[{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {{case_clause,[5,2,3]},
            [{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]} **

As you can see, the reason is still {case_clause,...}. In complex code, you would not easily figure out which case caused the problem. Let us fix the code:

 1: function(Operation,Values) ->
 2:   case Operation of
 3:     null -> 
 4:       null;
 5:     multiply ->
 6:       do_multiply(Values)
 7:   end.
 8: 
 9: do_multiply([Value1,Value2]) when integer(Value1),
10:                                   integer(Value2)->
11:   {ok,Value1*Value2}.

If we pass an invalid operation:

(rvg@davinci)11> test:function(divide,[5,2]).

=ERROR REPORT==== 25-Dec-2004::20:37:54 ===
Error in process <0.60.0> on node 'rvg@davinci' with exit value: 
{{case_clause,divide},[{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]} 

** exited: {{case_clause,divide},
            [{test,function,2},{shell,exprs,6},{shell,eval_loop,3}]} **

You can see that the case clause in function(...) cannot handle the divide atom. If we pass invalid parameters:

(rvg@davinci)12> test:function(multiply,[5,2,3]). 

=ERROR REPORT==== 25-Dec-2004::20:38:54 ===
Error in process <0.62.0> on node 'rvg@davinci' with exit value:
 {function_clause,[{test,do_multiply,5,2,3},{erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {function_clause,[{test,do_multiply,5,2,3},
                             {erl_eval,do_apply,5},
                             {shell,exprs,6},
                             {shell,eval_loop,3}]} **

It is clear that the problem is in do_multiply(...)