0
votes

I am copy a gen_server implementation code from Learn you some erlang for great good, and create a file named kitty_gen_server.erl. then I run following command in erlang shell:

$ erl
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Eshell V8.0.2  (abort with ^G)
1> c(kitty_gen_server).
{ok,kitty_gen_server}
2> P = kitty_gen_server:start_link().
{ok,<0.64.0>}
3> kitty_gen_server:close_shop(P).
** exception exit: {{function_clause,
                        [{gen,do_for_proc,
                             [{ok,<0.64.0>},#Fun<gen.0.62797829>],
                             [{file,"gen.erl"},{line,253}]},
                         {gen_server,call,2,[{file,"gen_server.erl"},{line,200}]},
                         {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
                         {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
                         {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
                         {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]},
                    {gen_server,call,[{ok,<0.64.0>},terminate]}}
     in function  gen_server:call/2 (gen_server.erl, line 204)
4>

I am sure the code is right download from learn you some erlang for greate good, But I don know why cannot excute.

My system is OS X 10.11, Erlang 19.

this following is code:

-module(kitty_gen_server).
-behaviour(gen_server).

-export([start_link/0, order_cat/4, return_cat/2, close_shop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

-record(cat, {name, color=green, description}).

%%% Client API
start_link() ->
    gen_server:start_link(?MODULE, [], [{debug,[trace]}]).

%% Synchronous call
order_cat(Pid, Name, Color, Description) ->
   gen_server:call(Pid, {order, Name, Color, Description}).

%% This call is asynchronous
return_cat(Pid, Cat = #cat{}) ->
    gen_server:cast(Pid, {return, Cat}).

%% Synchronous call
close_shop(Pid) ->
    gen_server:call(Pid, terminate).

%%% Server functions
init([]) -> {ok, []}. %% no treatment of info here!

handle_call({order, Name, Color, Description}, _From, Cats) ->
    if Cats =:= [] ->
        {reply, make_cat(Name, Color, Description), Cats};
       Cats =/= [] ->
        {reply, hd(Cats), tl(Cats)}
    end;
handle_call(terminate, _From, Cats) ->
    {stop, normal, ok, Cats}.

handle_cast({return, Cat = #cat{}}, Cats) ->
    {noreply, [Cat|Cats]}.

handle_info(Msg, Cats) ->
    io:format("Unexpected message: ~p~n",[Msg]),
    {noreply, Cats}.

terminate(normal, Cats) ->
    [io:format("~p was set free.~n",[C#cat.name]) || C <- Cats],
    ok.

code_change(_OldVsn, State, _Extra) ->
    %% No change planned. The function is there for the behaviour,
    %% but will not be used. Only a version on the next
    {ok, State}. 

%%% Private functions
make_cat(Name, Col, Desc) ->
    #cat{name=Name, color=Col, description=Desc}.
1

1 Answers

4
votes

kitty_gen_server:start_link/0 returns a tuple {ok, Pid} on success which you're storing directly in P, so your next call passes {ok, Pid} to kitty_gen_server:close_shop/1 instead of just the Pid. You need to use pattern matching to only store the Pid in P:

1> c(kitty_gen_server).
{ok,kitty_gen_server}
2> {ok, P} = kitty_gen_server:start_link().
{ok,<0.64.0>}
3> kitty_gen_server:close_shop(P).
ok