Consider the following code:
1... f(X) -> 2... Y = g(X), 3... h(Y, X), 4... p(Y), 5... f(12).
f(X) ->
case g(X) of
true -> A = h(X), B = 7;
false -> B = 6
end,
...,
h(A),
...
If the true branch of the form is evaluated, the variables A
and B become defined, whereas in the false branch only B
is defined.Whether or not this an error depends upon what happens after the case function. In this example it is an error, a future reference is made to A in the call h(A) - if the false branch of the case form had been evaluated then A would have been undefined.
-module(try).
-export([foo/1]).
foo(1) -> hello;
foo(2) -> throw({myerror, abc});
foo(3) -> tuple_to_list(a);
foo(4) -> exit({myExit, 222}).
try:foo(1) evaluates to hello. try:foo(2) tries to evaluate throw({myerror, abc}) but no catch exists. The process evaluating foo(2) exits and the signal {`EXIT',Pid,nocatch} is broadcast to the link set of the process.
try:foo(3) broadcasts {`EXIT', Pid, badarg} signals to all linked processes.
try:foo(4) since no catch is set the signal {`EXIT',Pid,{myexit, 222}} is broadcast to all linked processes.
try:foo(5) broadcasts the signal {`EXIT',Pid,function_clause} to all linked processes.
catch try:foo(1) evaluates to hello.
catch try:foo(2) evaluates to {myError,abc}.
catch try:foo(3) evaluates to {`EXIT',badarg}.
catch try:foo(4) evaluates to {`EXIT',{myExit,222}}.
catch try:foo(5) evaluates to {`EXIT',function_clause}.
f(X) ->
case catch func(X) of
{`EXIT', Why} ->
... error in BIF ....
........ BUG............
{exception1, Args} ->
... planned exception ....
Normal ->
.... normal case ....
end.
func(X) ->
...
func(X) ->
bar(X),
...
...
bar(X) ->
throw({exception1, ...}).
...
If a call is made to Mod:Func(Arg0,...,ArgN) and no code
exists for this function then
undefined_call(Mod, Func,[Arg0,...,ArgN])
in the module error_handler will be called.
The code in error_handler is almost like this:
-module(error_handler).
-export([undefined_call/3]).
undefined_call(Module, Func, Args) ->
case code:if_loaded(Module) of
true ->
%% Module is loaded but not the function
...
exit({undefined_function, {Mod, Func, Args}});
false ->
case code:load(Module) of
{module, _} ->
apply(Module, Func, Args);
false ->
....
end.
By evaluating process_flag(error_handler, MyMod) the user
can define a private error handler. In this case the
function:MyMod:undefined_function will be called instead
of error_handler:undefined_function.
Note:This is extremely dangerous
-module(m).
-export([start/0,server/0]).
start() ->
spawn(m,server,[]).
server() ->
receive
Message ->
do_something(Message),
m:server()
end.
When the function m:server() is called then a call is made
to the latest version of code for this module.If the call had been written as follows:
server() ->
receive
Message ->
do_something(Message),
server()
end.
Then a call would have been made to the current
version of the code for this module.Prefixing the module name (i.e. using the : form of call allows the user to change the executing code on the fly.
The rules for evaluation are as follows:

"C" should check return value from read. See p.259 in the book for more info.
Erlang references are unique, the system guarantees that no two references created by different calls to make_ref will ever match. The guarantee is not 100% - but differs from 100% by an insignificantly small amount :-).
References can be used for writing a safe remote procedure call interface, for example:
ask(Server, Question) ->
Ref = make_ref(),
Server ! {self(), Ref, Question},
receive
{Ref, Answer} ->
Answer
end.
server(Data) ->
receive
{From, Ref, Question} ->
Reply = func(Question, Data),
From ! {Ref, Reply},
server(Data);
...
end.
sum([H|T]) ->
H + sum(T);
sum([]) ->
0.
Note that we canot Evaluate '+' until both its arguments are known.
This formulation of
sum(X) evaluates in
space O(length(X)).The second is a tail recursive which makes use of an accumulator Acc:
sum(X) ->
sum(X, 0).
sum([H|T], Acc) ->
sum(T, H + Acc);
sum([], Acc) ->
Acc.
The tail recursive
formulation of sum(X).
Evaluates in constant
space.Tail recursive = the last thing the function does is to call itself.
For example:
server(Date) ->
receive
{From, Info} ->
Data1 = process_info(From, Info, Data),
server(Data1);
{From, Ref, Query} ->
{Reply, Data1} = process_query(From, Query,Data),
From ! {Ref, Reply},
server(Data1)
end.
Note that the last thing to be done in any thread of
computation must be to call the server.