catching errors from linked processes: simplest way?

Chris Pressey cpressey@REDACTED
Tue Apr 22 22:35:16 CEST 2003


On Tue, 22 Apr 2003 08:30:14 +0200
Lennart Öhman <lennart.ohman@REDACTED> wrote:

> Hi
> 
> Chris Pressey wrote:
> > OK, so, I'm actually trying to write 'aggressively simple' code now,
> 
> Good! :-)
> 
> The "aggressive way" when having several processes is to have one (or
> possibly several if it is a complicated system) process which
> supervises the other(s). In this way you move all the error handling,
> if you need it at all, away from the code implementing the logic.
> 
> You should then try to write the code in a way that the logic works
> fine without the supervision (during normal input). The supervision is
> then only an add-on to provide robustness.
> 
> /Lennart

OK!  I wrote a supervisor process to catch errors from both the client
and the server, and it works fairly well.

However, I got to another sticking point.  I have several functions that
only make sense under a certain condition, let's call it A.  The
functions used to look like this:

  foo(A, B) ->
    case A of
      true ->
        bar(B);
      false ->
        {error, only_applies_under_condition_a}
    end.

Now, they look like this:

  foo(A, B) ->
    A = true, bar(B).

which is *much* easier to read.  :)

However, the error message has gone from a nice, informative one, to the
generic {badmatch, true}, which is not all that great (I'd like to be
able to give the (probably non-Erlang-literate) user a message as to
exactly why it crashed.)

I can think of two ways to handle this: either translate the error in
the client, or translate the error in the supervisor.

If I do the translation in the client, I would have:

  foo(A, B) ->
    case A of
      true ->
        bar(B);
      false ->
        throw(only_applies_under_condition_a)
    end.

which is hardly any improvement over the original.

If I do the translation in the supervisor, I would have something like:

  process_flag(trap_exits, true),
  receive
    ...
    {'EXIT', Client, {{badmatch, true}, [{module,foo,2} | Tail]}} ->
      io:fwrite("Client code violated condition A~n");
    ...
  end.

This is worrisome.

First, if I change the implementation of the client, say if I move what
foo does to another function, then I have to change the supervisor code
to reflect it.

Second, the supervisor is inferring (guessing!) that condition A was
violated because it knows that it's the only one in foo.  If there were
two or more invariants in foo, it wouldn't know which one was violated.

I guess the underlying 'problem' is that there's no way (that I'm aware
of) to pass along some state when an error occurs, without causing that
error yourself.  I think such a thing would be really very handy,
especially when I consider things like encountering an error when
parsing a text file - you would want the supervisor to know which line,
column, and token you choked on.

Or is this just 'too aggressive'?  It seems there is a time and place
for error return values instead of crashing, and this may be it.

-Chris



More information about the erlang-questions mailing list