| Author |
Message |
|
| luke at javagroup.org |
Posted: Thu Jun 17, 1999 4:10 pm |
|
|
|
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) |
|
|
| Back to top |
|
| ulf.wiger at etx.ericsson |
Posted: Thu Jun 17, 1999 6:10 pm |
|
|
|
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.
>
> 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
--
Ulf Wiger, Chief Designer AXD 301 <ulf.wiger_at_etx.ericsson.se>
Ericsson Telecom AB tfn: +46 8 719 81 95
Varuv |
|
|
| Back to top |
|
|
|
All times are GMT
|
|
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
|
|
|