Erlang Mailing Lists

Author Message

<  Erlang questions mailing list  ~  Style with gen_server

luke at javagroup.org
Posted: Thu Jun 17, 1999 4:10 pm Reply with quote
Guest
Hi guys,

I'm having my first poke around with gen_server, and I have a question
about the style its used with. I also note that what I'm trying to do
is fairly "object-oriented", so if there's a different mindset which
would be more appropriate for this problem in Erlang, please let me
know. :)

Basically, what I want to do is implement polymorphism. The neatest
way to do it seems to be using anonmyous gen_server processes which
all expect the same sorts of messages, and then build a client module
to encapsulate the gen_server:call stuff. So, I'll have some modules:

my_client: no 'behaviour'. maps calls like wash(Pid, Dishes) to
gen_server:call(Pid, {wash, Dishes}, infinity).

dishwasher: implements gen_server behaviour. used as with:
{ok,Pid} = gen_server:start_link(dishwasher,[],[]),
my_client:wash(Pid, SomeDishes).
slave: as above, but with a different implementation

Is this the right way to go? Sorry if this seems terribly obvious, I
just want to check that I'm thinking the right way. :)

Also, I suppose that if I wanted throw an exception at the caller, the
best way would be to stick something in my_client like:

wash(Pid,Dishes) ->
case gen_server:call(Pid, {wash,Dishes}) of
{ok,Result} -> Result;
{error,Reason} -> throw(Reason)
end.

Right?

Cheers,
Luke




Post generated using Mail2Forum (http://m2f.sourceforge.net)
ulf.wiger at etx.ericsson
Posted: Thu Jun 17, 1999 6:10 pm Reply with quote
Guest
dishwasher.erl:

new() ->
gen_server:start_link(?MODULE, [], []).

wash(DishWasher, Dishes) ->
call(DishWasher, {wash, Dishes}).


%%% internal exports
init(_) ->
{ok, #state{}}.

handle_call({wash, Dishes}, From, State) ->
{Result, NewState} = do_wash(Dishes, State),
{reply, Reply, NewState}.


%%% internal functions

%%% "Aggressive" behaviour on the client side.
%%% The function either succeeds or exits.
call(DW, Req) ->
case gen_server:call(DW, Req) of
{error, Reason} ->
exit(Reason);
Other ->
Other
end.

...USW


Useage:

clean(DirtyDishes) ->
MyDishWasher = dishwasher:new(),
CleanDishes = dishwasher:wash(MyDishWasher, DirtyDishes).

No need for "if" statements on the return value, since there will be an
EXIT if something goes wrong. Remember, EXITs can always be caught at
some level suitable for error handling.


Summary (in object terms):

- The module name represents the type of object
- The API function is the method call (ObjectType:Method(Instance,
Args))
- Hide the gen_server details in dishwasher.erl
- (my preference): Write functions that either succeed or EXIT

I prefer using exit() instead of throw(), partly because throw() assumes
a catch -- if there's no catch, you will get an {'EXIT', nocatch}, which
isn't very helpful.

One way to structure things:

- Use throw({error, Reason}) to bail out to a top-level catch if
it is a controllable error
- Use exit(Reason) for everything else
- Use catch Expr at lower levels only in special cases
- Possibly use throw(GoodResult) as a non-local return sometimes

/Uffe

Luke Gorrie wrote:
>
> Hi guys,
>
> I'm having my first poke around with gen_server, and I have a question
> about the style its used with. I also note that what I'm trying to do
> is fairly "object-oriented", so if there's a different mindset which
> would be more appropriate for this problem in Erlang, please let me
> know. Smile
>
> Basically, what I want to do is implement polymorphism. The neatest
> way to do it seems to be using anonmyous gen_server processes which
> all expect the same sorts of messages, and then build a client module
> to encapsulate the gen_server:call stuff. So, I'll have some modules:
>
> my_client: no 'behaviour'. maps calls like wash(Pid, Dishes) to
> gen_server:call(Pid, {wash, Dishes}, infinity).
>
> dishwasher: implements gen_server behaviour. used as with:
> {ok,Pid} = gen_server:start_link(dishwasher,[],[]),
> my_client:wash(Pid, SomeDishes).
> slave: as above, but with a different implementation
>
> Is this the right way to go? Sorry if this seems terribly obvious, I
> just want to check that I'm thinking the right way. Smile
>
> Also, I suppose that if I wanted throw an exception at the caller, the
> best way would be to stick something in my_client like:
>
> wash(Pid,Dishes) ->
> case gen_server:call(Pid, {wash,Dishes}) of
> {ok,Result} -> Result;
> {error,Reason} -> throw(Reason)
> end.
>
> Right?
>
> Cheers,
> Luke

--
Ulf Wiger, Chief Designer AXD 301 <ulf.wiger_at_etx.ericsson.se>
Ericsson Telecom AB tfn: +46 8 719 81 95
Varuv

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum