Exception handling idioms

Ulf Wiger (AL/EAB) ulf.wiger@REDACTED
Mon Aug 29 09:29:35 CEST 2005

Tim Bates:
> That is nice, but what if the error is generated deep
> in a function called by handle_call? And if I want to
> return an error code to the calling process without
> crashing it or the server?

In general, I'd say it's a very good idea to check as much
as possible as early as possible, but of course, it might 
happen that you have to go deep down into the logic before
you can detect that the request was invalid.

This would be a pretty good occasion for throw and the 
new try ... catch syntax.

> Then I have to do lots of explicit {error, ...} kind of
> stuff which the exception handling mechanisms are supposed
> to help me avoid, or I have to wrap the contents of every 
> clause of handle_call in a try.

Not every handle_call(...) ... well, yes, every handle_call(),
but you only write one:

handle_call(Request, From, State) ->
   Reply = 
      try my_handle_call(Request, From, State) of
         R -> {ok, R}
         throw:Error ->
              {error, Error}
   {reply, Reply, State}.

This will catch only throws -- not programming errors,
and it's of course desirable not to force the client 
to crash due to a programming error in the server, 
and let the server continue as if it were without fault.

 Perhaps I could extend 
> gen_server to catch non-local returns, ie throw(), and 
> re-raise them in 
> the calling process. But that still doesn't work for 
> gen_server:cast(). 

With the construct above, you don't have to mess with 
the gen_server itself.

And as far as gen_server:cast() goes, any checking that 
would raise an exception in the client would have to be
before the message is sent to the server -- i.e. on the 
client side. Otherwise, you have to use gen_server:call().
This is not so much a technical problem as it is a 
matter of principle: immediately after a cast, the client
goes its own merry way, and doesn't concern itself with
any consequences that the cast may have on the server
side. If there is to be a reckoning, the client should 
use a gen_server:call() and wait for judgement.


More information about the erlang-questions mailing list