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.
Suppose we have defined the following:try:foo(1) evaluates to hello.-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(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.
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, Data} = 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.