I'm making this call:
add(Login, Pass, Role) ->
gen_server:call(?SERVER, {add, Login, Pass, Role}).
and I expect it to match with:
handle_call(State, {add, Login, Pass, Role}) ->
io:format("add ~n"),
Db = State#state.db,
case lists:keyfind(Login, 1, Db) of
false->
io:format("add - reg new ~n"),
{reply, registered, State#state{db=[{Login, erlang:md5(Pass), Role, ""}|Db]}};
{Key, Result}->
{reply, invalid_params, Db}
end.
but it always goes to:
handle_call(_Request, _From, State) ->
io:format("undef ~n"),
Reply = ok,
{reply, Reply, State}.
What's wrong?
The behaviour seems valid,
handle_call has such spec:
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
State :: #state{}) ->
{reply, Reply :: term(), NewState :: #state{}} |
{reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
{noreply, NewState :: #state{}} |
{noreply, NewState :: #state{}, timeout() | hibernate} |
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
{stop, Reason :: term(), NewState :: #state{}}).
If you can take a look here
http://erlang.org/doc/man/gen_server.html#Module:handle_call-3
Also, for otp default behaviours, it would be the best, as a start, to use templates. For gen_server eg https://gist.github.com/kevsmith/1211350
Cheers!
In a module using the gen_server behaviour, the handle_call callback function should take three arguments. However, you have defined two different functions, handle_call/2 and handle_call/3. (In Erlang, functions that have the same name but take different numbers of arguments are considered different functions.)
Since the gen_server module only looks for handle_call/3 and ignores handle_call/2, your "undef" function is always called.
To fix this, change the function to take an (ignored) second argument, and put the request first and the state last:
handle_call({add, Login, Pass, Role}, _From, State) ->
and change the end. to end; — . separates different functions, while ; separates different clauses of the same function.
Related
I can understand why a callback module must provide init and handle_call functions. init is for creating the initial state, and handle_call is the main purpose for creating a server process: to serve requests.
But I don't understand why handle_cast is required. Couldn't gen_server module provide a default implementation, like it does for many other callbacks? It could be a noop like
handle_cast(_, State) -> {noreply, State}.
It seems to me that the majority of callback modules provide noops like this one anyway.
handle_cast is similar to handle_call, and is used for asynchronous calls to the gen_server you're running (calls are synchronous). It is handling requests for you, just not with a reply as a call does.
Similarly to gen_call it can alter the state of your gen_server (or leave it as is, up to your needs and implementation). Also it can stop your server, hibernate, etc. just like your calls - see learn you some erlang for examples and a broader explanation.
It "can be a noop" as you said in the question, but in some cases it's better to implement and handle async calls to your server.
and handle_call is the main purpose for creating a server process: to serve requests.
The client-server architecture can be applied to a much wider range of problems than merely a web server that serves up documents. One example is the frequency server discussed in several erlang books. A client can request a frequency from the server for making a phone call, then the client must wait for the server to give return a specific frequency before a call can be made. That is a classic gen_server:call() situation: the client must wait for the server to return a frequency before the client can make a phone call.
However, when the client is done using the frequency the client sends a message to the server telling the server to deallocate the frequency. In that case, the client does not need to wait for a response from the server because the client doesn't even care what the server's response is. The client just needs to send the deallocate message, then the client can continue executing other code. It's the server's responsibility to process the deallocate message when it has time, then move the frequency from a "busy" list to a "free" list, so that the frequency is available for other clients to use. As a result, a client uses gen_server:cast() to send a deallocate message to the server.
Now, what is the "main purpose" of the frequency server? To allocate or deallocate frequencies? If the server doesn't deallocate frequencies, then after a certain number of client requests, there won't be any more frequencies to hand out and clients will get a message that says "no frequencies available". Therefore, for the system to work correctly the act of deallocating frequencies is essential. In other words, handle_call() is not the "main purpose" of the server--handle_cast() is equally important--and both handlers are needed to keep the system running as efficiently as possible.
Couldn't gen_server module provide a default implementation, like it
does for many other callbacks?
Why can't you create a gen_server template, which has a default implementation of handle_cast() yourself? Here's emac's default gen_server template:
-behaviour(gen_server).
%% API
-export([start_link/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% #doc
%% Starts the server
%%
%% #spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% #end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% #private
%% #doc
%% Initializes the server
%%
%% #spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% #end
%%--------------------------------------------------------------------
init([]) ->
{ok, #state{}}.
%%--------------------------------------------------------------------
%% #private
%% #doc
%% Handling call messages
%%
%% #spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% #end
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% #private
%% #doc
%% Handling cast messages
%%
%% #spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% #end
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% #private
%% #doc
%% Handling all non call/cast messages
%%
%% #spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% #end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% #private
%% #doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% #spec terminate(Reason, State) -> void()
%% #end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% #private
%% #doc
%% Convert process state when code is changed
%%
%% #spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% #end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
Here is an example trace where I'm able to call erlang:monitor/2 on the same Pid:
1> Loop = fun F() -> F() end.
#Fun<erl_eval.30.99386804>
2> Pid = spawn(Loop).
<0.71.0>
3> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126937>
4> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126942>
5> erlang:monitor(process, Pid).
#Ref<0.2485499597.1470627842.126947>
The expressions returned by instruction #4 and #5 are different than #3, meaning that it is possible to create multiple monitor references between the current process and Pid. Is there a practical case where you would need or use multiple monitor references to the same process?
I would expect this to return the same reference (returning a new one would perhaps imply that the old one had failed/crashed), following the same logic that exists for link/1.
Imagine you use third party library which does this (basically what OTP *:call/* functions does):
call(Pid, Request) ->
call(Pid, Request, ?DEFAULT_TIMEOUT).
call(Pid, Request, Timeout) ->
MRef = erlang:monitor(process, Pid),
Pid ! {call, self(), MRef, Request},
receive
{answer, MRef, Result} ->
erlang:demonitor(Mref, [flush]),
{ok, Result};
{'DOWN', MRef, _, _, Info} ->
{error, Info}
after Timeout ->
erlang:demonitor(MRef, [flush]),
{error, timeout}
end.
and then you use it in your code where you would monitor the same process Pid and then call function call/2,3.
my_fun1(Service) ->
MRef = erlang:monitor(process, Service),
ok = check_if_service_runs(MRef),
my_fun2(Service),
mind_my_stuf(),
ok = check_if_service_runs(MRef),
erlang:demonitor(MRef, [flush]),
return_some_result().
check_if_service_runs(MRef) ->
receive
{'DOWN', MRef, _, _, Info} -> {down, Info}
after 0 -> ok
end.
my_fun2(S) -> my_fun3(S).
% and a many layers of other stuff and modules
my_fun3(S) -> call(S, hello).
What a nasty surprise it would be if erlang:monitor/2,3 would always return the same reference and if erlang:demonitor/1,2 would remove your previous monitor. It would be a source of ugly and unsolvable bugs. You should start to think that there are libraries, other processes, your code is part of a huge system and Erlang was made by experienced people who thought it through. Maintainability is key here.
Looking at Erlang docs, sometimes I come across type specs, that document a function type without really specifying the type...
Hard to explain, so let me give you an example. In the gen_server the handle_call function shows up as the following in the docs:
Request = term()
From = {pid(),Tag}
State = term()
Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}
| {reply,Reply,NewState,hibernate}
| {noreply,NewState} | {noreply,NewState,Timeout}
| {noreply,NewState,hibernate}
| {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
Reply = term()
NewState = term()
Timeout = int()>=0 | infinity
Reason = term()
Here the type Tag is never shown (i.e. it's just a variable name).
Is the same possible to do with edoc? The closest I found was opaque type spec, but that documents it as abstract - is that the same?
It is possible as long as the argument variable name in the function (in all clauses) and that name used in the #spec are same. For example.
%% #spec start_link(Args) -> {ok, pid()}
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
will generate the following doc
start_link(Args) -> {ok, pid()}
If you have a different name for example
%% #spec start_link(Args) -> {ok, pid()}
start_link(Num) when is_integer(Num) ->
gen_server:start_link(?MODULE, [], []);
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
It would generate as
start_link(Num::Args) -> {ok, pid()}
assuming Args as a type.
I would personally not recommend to use edoc #spec and instead use -spec as they are used by dialyzer and hence can be validated.
edoc can generate the doc from -spec too. Given both -spec and #spec, edoc overrides to #spec directive.
%% #spec start_link(Args) -> {ok, Pid}
-spec start_link(term()) -> {ok, pid()}.
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
Above will result in
start_link(Args) -> {ok, Pid}
And removing #spec from above will result in
start_link(Args::term()) -> {ok, pid()}
As far as I can see, this is not possible with Edoc.
I tried using a spec like this:
-spec foo(Something) -> term().
foo(X) ->
X.
And while Edoc is actually happy about it, and gives the type spec as foo(Something) in the docs without specifying what Something is, the compiler complains about it, and says:
type variable 'Something' is only used once (is unbound)
So you'd have to write:
-spec foo(Something::_) -> term().
foo(X) ->
X.
which shows up as foo(Something::term()), thereby giving a type specification for Something.
Using an Edoc-only type specification:
%% #spec foo(Something) -> term()
foo(X) ->
X.
Edoc treats Something as a type name that applies to the variable X and puts foo(X::Something) in the documentation.
So neither way would do exactly what you want to achieve.
What's correct Erlang way to have separated implementations from the contract and how to switch between them?
While others mention the behaviour feature, it is merely a small helper to make sure you implement all functions in a module for a callback structure. If you have two implementations, a and b, and both implements the same functions, you can just statically substitute a for b in a calling module. For static configuration where you have a better implementation, this is preferable.
If the question is of a more dynamic nature, you can just do
Mod = a,
Mod:f(Args).
And then in code set Mod appropriately. This lets you dynamically control what module to call while the program is running. It is not entirely clear which of the two you want.
Nice example of polymorphism is qlc module and structure table. See various M:table/1,2 implementations in ets, dets, mnesia and so. Try ets:table(ets:new(foo, [set])). in shell for example and look into qlc documentation and examples.
Since Erlang is dynamically typed, function guards (the when … -> bits) are the way to express polymorphism.
E.g:
len (T) when is_tuple(T) -> size(T);
len (L) when is_list(L) -> length(L).
Maybe have a look on behaviours concept. At least for me there is small similarity to OOP in terms of having interface definition and multiple implementation modules.
If I realized your question, here is example for approach, that pretty much works for me. This approach helps to separate interface and implementation.
"Interface" module.
-module(contract).
-export([
new/2,
do_something/2
]).
%% Behavioural callbacks definition. Each of "derived" modules should implement it.
-callback new(Arg :: any()) -> {ok, ImplState :: any()} | {error, Reason :: atom()}.
-callback do_something( Arg :: any(), ImplState :: any() ) -> {ok, ReturnVal :: any(), NewImplState :: any()} | {error, Reason :: atom()}.
%% Opaque state to hold implementation details
-record(
contract_impl, {
impl_module :: module(),
impl_state :: any()
}
).
%% Interface for creation "polymorphic" instance, like base-class constructor.
new(ImplModule, ImplInitArgs) ->
case ImplModule:new(ImplInitArgs) of
{ok, State} ->
{ok,
#contract_impl {
impl_module = ImplModule,
impl_state = State
}
};
{error, Reason} ->
{error, Reason}
end.
%% Interface function, like an abstract method in OOP.
do_something(
Arg,
#contract_impl {
impl_module = ImplModule,
impl_state = ImplState
} = ContractImpl
) ->
case ImplModule:do_something(Arg, ImplState) of
{ok, ReturnVal, NewState} ->
{ok, ReturnVal, ContractImpl#contract_impl{ impl_state = NewState }};
{error, Reason} -> {error, Reason}
end.
Some implementation example (like derived class).
-module(foo).
-behaviour(contract).
-export([
new/1,
do_something/2
]).
-record(
foo_state, {
repeat_count
}
).
new(Options) ->
{ok,
#foo_state{
repeat_count = proplists:get_value(repeat_count, Options)
}
}.
do_something(Arg, #foo_state{ repeat_count = RepeatCount } = State) ->
Result = [ io_lib:format("Foo ~p", [Arg]) || _Index <- lists:seq(1, RepeatCount) ],
{ok, Result, State}.
Now you can do the following:
usage_example() ->
{ok, State} = contract:new(foo, [{repeat_count, 15}]),
{ok, Result, NewState} = contract:do_something("bar", State),
ok.
I hope this helps.
Say I have some function fn1() in Erlang which returns {ok, Result} if the function was executed successfully and {error, "ErrorReason"} if there was an error.
Now in another function fn2() I call fn1() and I need to check the result of fn1 and proceed only if it is {ok, Result}.
I figured, I can do this using either case or try catch. But Efficiency is my main concern and I'd like to know which of the two methods below is more efficient:
try-catch Method
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
case Method
fn2() ->
Res = fn1(),
case Res of
{ok, Result} ->
%Do something with Result
ok;
{error, Reason} ->
Reason
end.
You really want to try and avoid try/catch like the plague. It is a very uncommon idiom in Erlang - really only used in a couple of special cases:
where you are checking user-supplied
input and you have no guarantees that
it will be 'correct'
where you have something which is
deeply nested and the cost of
unrolling it on an error condition
is too expensive
like mensia transactions
or in parser/lexer's
Try/catch is essential in languages like C++ where the application is unstable in the presence or errors, but Erlang is stable in those circumstances - the process crashes but doens't bring the system down.
You should programme the happy path, match return values and if the application deviates from what you expect then let it crash. The crash tells you you have a problem and tells you to fix it.
The problem with try/catch is that it can simply mask the problem, or even worse, move the eventual crash away from where it should happen (inside the expression you have wrapped) and make it appear elsewhere - where your programming logic expects it to have suceeded = which makes debugging much harder.
Programming the happy path and letting it crash is very disconcerting the first time you do it, it feels like going out with no clothes on, but actually you get used to it real quick :)
The case method will be more efficient, as it simply pattern matches, and does not involve building a call stack and stuff.
In both examples you are about to handle the "error" locally, so there is no point in the try catch.What you might see sometimes is something like:
fn2() ->
{ok, Result} = fn1(),
%Do stuff with Result
ok.
Here the intention is that you make fn2() throw a badmatch, if fn1() did not return ok. You let someone else "above" handle the problem. E.g. this might kill your process, and make your supervisor create a new one.
You should always measure to find things like this out.
Your code also does not do what you think it does.
-module(glurk).
-compile(export_all).
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
fn1() ->
{error, a}.
Try this out:
c(glurk).
./glurk.erl:6: Warning: variable 'Result' is unused
{ok,glurk}
16> glurk:fn2().
{error,{{badmatch,{error,a}},
[{glurk,fn2,0},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}}
This is because fn1 did not raise an exception
it gebnerated a normal retyurn value {error, a} which
does not pattern match against {ok, Result}
The first version of your code works with a function that either returns a normal value
or raises an exception - you have to write it like this:
fn1(....) ->
...
%% success case
Val;
%% failure case
throw(...) | exit(...) | error(...)
You can't just pump the same function into fn1 and fn2.
If you had the case where the called function had to escape from a deep recursion
then the first method would be more efficient than the second - since you could
immediately exit from a deep recursion by saying throw(...).
So the answer depends upon the nature of the function that you are calling.
Code should always be optimised for beauty and not efficiency - since you have
to maintain the stuff - then it should only be optimised in the rare cases
where it is not fast enough. What needs to be optimised should be identified
by measuring the program (you will always be surprised here :-)
Me, I'd write
{ok,Result} = ...
Actually your first code has a more subtle error
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
Think about this. The caught error cases do not themselves handle the error
they just return tuples like {exit, Reason} or {error, Reason} this means that the
next layer up (ie the caller of fn2) will also have to mess around checking
error returns - if this is repeated at all levels the code will be a mess.
The "erlang" way is to have one try-catch at the top of the program and just terminate
abruptly with exit(Why) if an error occurs.
In fact often you should not even do this - you should link your process to another process
then the offending process will die and "the other processes will fix the error".
The exception propagates up the call stack and flies over to the linked processes
for treatment. So we have two types of processes - ones that have no inbuilt error handling
and processes that only do error handling.
In this case, irrespective of what is more efficient, you should definitely use the case alternative as it more succinctly describes what is going on. Your fn1() here return a value indicating if there is a successful value or an error. In the case version you directly match against this, while in the try version you match against the success value which will generate an error if an error was returned. It is unnecessarily convoluted and hides what is going on so it is bad programming style and should be avoided.
And as Gordon has already pointed out having a try there will catch more errors than you probably intend and may so mask other real errors which you should see.
The case will also be faster here, but the difference is probably small. The clarity, succinctness and good programming style is much more important!
The case will always be more efficient, but the difference is small and it's more important what makes more sense in your particular case. Especially, which approach produces more understandable code. See this benchmark:
%% Results:
%% 7> errors:run_normal(100).
%% {9,ok}
%% 8> errors:run_normal(1000).
%% {107,ok}
%% 9> errors:run_normal(10000).
%% {856,ok}
%% 10> errors:run_normal(1000, 10).
%% {263,ok}
%% 11> errors:run_wcatch(10000).
%% {2379,ok}
%% 12> errors:run_wcatch(1000, 10).
%% {401,ok}
%% 18> errors:run_normal_cplx(10000, 50).
%% {7910,ok}
%% 19> errors:run_wcatch_cplx(10000, 50).
%% {10222,ok}
-module(errors).
-compile(export_all).
run_normal(Iterations) ->
get_result(Iterations, fun() -> normal() end).
run_normal(Iterations, Level) ->
get_result(Iterations, fun() -> deepnormal(Level) end).
run_wcatch(Iterations) ->
get_result(Iterations, fun() -> wcatch() end).
run_wcatch(Iterations, Level) ->
get_result(Iterations, fun() -> deepwcatch(Level) end).
run_normal_cplx(Iterations) ->
get_result(Iterations, fun() -> normal_complex() end).
run_normal_cplx(Iterations, Level) ->
get_result(Iterations, fun() -> deepnormal_complex(Level) end).
run_wcatch_cplx(Iterations) ->
get_result(Iterations, fun() -> wcatch_complex() end).
run_wcatch_cplx(Iterations, Level) ->
get_result(Iterations, fun() -> deepwcatch_complex(Level) end).
%%------------------------------------------------------------------------------
get_result(Iterations, Fun) ->
timer:tc(fun() -> run(Iterations, Fun) end).
run(0, _Fun) ->
ok;
run(Iterations, Fun) ->
Fun(),
run(Iterations - 1, Fun).
%%------------------------------------------------------------------------------
normal() ->
case foo(atom) of
{ok, atom} -> ok;
{error, atom} -> ok
end.
normal_complex() ->
case foo_cplx() of
{ok, Res} -> Res;
{error, Res} -> Res
end.
deepnormal(Level) ->
case deepfoo(atom, Level) of
{ok, atom} -> ok;
{error, atom} -> ok
end.
deepnormal_complex(Level) ->
case deepfoo_cplx(Level) of
{ok, Res} -> Res;
{error, Res} -> Res
end.
wcatch() ->
try
{ok, atom} = foothrow(atom)
catch
throw:{error, atom} -> ok
end.
wcatch_complex() ->
try
{ok, _Res} = foothrow_cplx()
catch
throw:{error, Res} -> Res
end.
deepwcatch(Level) ->
try
{ok, atom} = deepfoothrow(atom, Level)
catch
throw:{error, atom} -> ok
end.
deepwcatch_complex(Level) ->
try
{ok, _Res} = deepfoothrow_cplx(Level)
catch
throw:{error, Res} -> Res
end.
%%------------------------------------------------------------------------------
foo(Arg) -> {error, Arg}.
foothrow(Arg) -> throw({error, Arg}).
deepfoo(Arg, 0) -> {error, Arg};
deepfoo(Arg, Level) -> deepfoo(Arg, Level - 1).
deepfoothrow(Arg, 0) -> throw({error, Arg});
deepfoothrow(Arg, Level) -> deepfoothrow(Arg, Level - 1).
foo_cplx() -> {error, {<<"Some">>, "Complex", data}}.
foothrow_cplx() -> throw({error, {<<"Some">>, "Complex", data}}).
deepfoo_cplx(0) -> {error, {<<"Some">>, "Complex", data}};
deepfoo_cplx(Level) -> deepfoo_cplx(Level - 1).
deepfoothrow_cplx(0) -> throw({error, {<<"Some">>, "Complex", data}});
deepfoothrow_cplx(Level) -> deepfoothrow_cplx(Level - 1).