> ## 3 Functions

> ### 3.1 Pattern matching

> Pattern matching in function, case and receive-clauses are optimized by the compiler. In most cases, there is nothing to gain by rearranging clauses.

> ### 3.2 Function Calls

> A function can be called in a number of ways and the cost differs a lot. Which kind of call to use depends on the situation. Below follows a table with the available alternatives and their relative cost.

> | The figures shown as relative cost is highly dependent on the implementation and will vary between versions and platform. The order from lowest to highest cost will however be stable and is very useful to be aware of.

> Type of call | Example | Relative cost (5.1)
> Local call | `foo()` | 1.00
> External call | `m:foo()` | 1.07
> Fun call | `Fun = fun(X) -> X + 1 end, Fun(2)` | 2.52
> Apply fun | `Fun = fun(X) -> X + 1 end, apply(Fun,[2])` | 3.32
> Apply MFA/3 | `apply(M, Foo, [])` or `M:Foo()` | 7.09
> Different ways of calling a function

> Apply is the most expensive way to call a function and should be avoided in time critical code. A well motivated use of apply is in conjunction with generic interfaces where several modules provide the same set of functions. The use of `apply/3` for just calling different functions within the same module (i.e `apply(mymodule,Func,Args)`) is not recommended. The use of Funs can often be a more efficient way to accomplish calls which are variable in runtime.

> The last entry in the table above shows the syntax `M:Foo(A1,A2,An)` (where M and Foo are bound variables) which is equivalent with `apply(M,Foo,[A1,A2,An])`. From an efficiency point of view it is recommended to use the `M:Foo(A1,A2,An)` form since this gives the compiler an opportunity to optimize the call in future versions.

> ### 3.3 Memory usage in recursion

> When writing recursive functions it is preferable to make them tail-recursive so that they can execute in a constant memory space.

> DO

>     list_length(List) ->
>         list_length(List, 0).

>     list_length([], AccLen) ->
>         AccLen; % Base case

>     list_length([_|Tail], AccLen) ->
>         list_length(Tail, AccLen + 1). % Tail-recursive

> DO NOT

>     list_length([]) ->
>         0. % Base case
>     list_length([_ | Tail]) ->
>         list_length(Tail) + 1. % Not tail-recursive

> ### 3.4 Unnecessary evaluation in each recursive step

> Do not evaluate the same expression in each recursive step, rather pass the result around as a parameter. For example imagine that you have the function in_range/3 below and want to write a function in_range/2 that takes a list of integers and atom as argument. The atom specifies a key to the named table range_table, so you can lookup the max and min values for a particular type of range.

>     in_range(Value, Min, Max) ->
>         (Value >= Min) and (Value =< Max).

> DO

>     in_range(ValuList, Type) ->
>         %% Will be evaluated only one time ...
>         [{Min, Max}] = ets:lookup(range_table, Type),
>         %% ... send result as parameter to recursive help-function
>         lists_in_range(ValuList, Min, Max).

>     lists_in_range([Value | Tail], Min, Max) ->
>         case in_range(Value, Min, Max) of
>             true ->
>                 lists_in_range(Tail, Min, Max);
>             false ->
>                 false
>         end;

>     lists_in_range([], _, _) ->
>         true.

> DO NOT

>     in_range([Value | Tail], Type) ->
>         %% Will be evaluated in each recursive step
>         [{Min, Max}] = ets:lookup(range_table, Type),
>         case in_range(Value, Min, Max) of
>             true ->
>                 lists_in_range(Tail, Type);
>             false ->
>                 false
>         end;

>     in_range([], _, _) ->
>         true.

Copyright © 1991-2003 Ericsson Utvecklings AB