Question

when executing the below code gen_server is raising an exception

    -module(drop).

    -behaviour(gen_server).

    -export([start_link/0]).

    -export([init/1,
     handle_call/3,
     handle_cast/2,
     handle_info/2,
     terminate/2,
     code_change/3]).

   -define(SERVER, ?MODULE).

   -record(state, {count}).

    start_link() -> 
          gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

    init([]) ->
         {ok, #state{count=0}}.

    handle_call(_Request, _From, State) ->
      Distance = _Request,
      Reply = {ok, fall_velocity(Distance)},
      NewState=#state{ count= State#state.count+1},
      {reply, Reply, NewState}.

    handle_cast(_Msg, State) ->
      io:format("so far, calculated ~w velocities.~n", [State#state.count]),
      {noreply, State}.

    handle_info(_Info, State) ->
      {noreply, State}.

    terminate(_Reason, _State) ->
        ok.  

    code_change(_OldVsn, State, _Extra) ->
            {ok, State}.

    fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).   

OUTPUT:

1> gen_server:call(drop, 60).
** exception exit: {noproc,{gen_server,call,[drop,60]}}
in function  gen_server:call/2 (gen_server.erl, line 180).

What's wrong in the above code? Do we need to compile the gen_server module after compiling the drop module?

Was it helpful?

Solution 2

The code you are testing works fine. As it is already said you need to start the gen_server. Here is the way to do it, and then ask some request:

1> c(drop).
{ok,drop}
2> S = spawn(drop,start_link,[]).
<0.40.0>
3> registered().
[rex,net_sup,inet_db,kernel_sup,global_name_server,
 code_server,file_server_2,init,kernel_safe_sup,
 application_controller,user,error_logger,user_drv,
 standard_error,global_group,standard_error_sup,drop,auth,
 erl_epmd,net_kernel,erl_prim_loader]
4> gen_server:call(drop,25).     
{ok,22.135943621178658}
5> gen_server:call(drop,13).
{ok,15.962455951387932}
6> gen_server:call(drop,20).
{ok,19.79898987322333}
7> gen_server:cast(drop,what).
so far, calculated 3 velocities.
ok

command 1 compiles the module. There is no need to compile the gen_server, it is already done in the Erlang libraries.

command 2 start the gen_server, generally in a module like drop, you add some interface function that hide this call something like start() -> spawn(?MODULE,start_link,[]). so you can start the server with simple call drop:start()

command 3 shows that the new process whas registered whith the name drop.

commands 4,5 and 6 ask for a velocity evaluation. As for start, the usage is to have an interface function such as velocity(N) -> gen_server:call(?MODULE,N) so you can simply call drop:velocity(25) the usage is also to "decorate" the message so you will be able to have more function later

command 7 use the message cast to get the number of velocities evaluated so far. Same remark about interface and decoration. here is a version more compliant with usage:

-module(drop).

-behaviour(gen_server).

%% interfaces
-export([start_link/0,velocity/1,so_far/0]).

-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {count}).

%% interfaces

start_link() -> 
    spawn (gen_server,start_link,[{local, ?SERVER}, ?MODULE, [], []]).

velocity(N) ->
  gen_server:call(?MODULE,{get_velocity,N}).

so_far() ->
  gen_server:cast(?MODULE,so_far). 

%% call back

init([]) ->
   {ok, #state{count=0}}.

handle_call({get_velocity,Distance}, _From, State) ->
  Reply = {ok, fall_velocity(Distance)},
  NewState=#state{ count= State#state.count+1},
  {reply, Reply, NewState};

handle_call(Request, _From, State) ->
  Reply = io:format("unknown request ~p~n",[Request]),
  {reply, Reply, State}.

handle_cast(so_far, State) ->
  io:format("so far, calculated ~w velocities.~n", [State#state.count]),
  {noreply, State};

handle_cast(Msg, State) ->
  io:format("unknown request ~p~n", [Msg]),
  {noreply, State}.

handle_info(_Info, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->
  ok.  

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.

fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).   

and now the commands look simpler:

12> drop:start_link().
<0.60.0>
13> drop:velocity(25).
{ok,22.135943621178658}
14> drop:velocity(20).
{ok,19.79898987322333}
15> drop:velocity(13).
{ok,15.962455951387932}
16> drop:so_far().    
so far, calculated 3 velocities.
ok

OTHER TIPS

no_proc -- means 'no process' -- you have not started your server.

Gen_server is a part of OTP architecture. It means you need to write application that starts supervisor which starts your drop server.

And then you can call it using gen_server:call

If you need just function to calculate velocity, you actually dont need OTP, you can export and call a function in the module.. Kind of

-module(drop).
-export([fall_velocity/1]).
 .....

and then invoke it

drop:fall_velocity(60).

BTW gen_server module is already compiled in the erlang libs.

You need to start your server before being able to interact with it via gen_server:call/2.

drop:start_link().
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top