ReRe: why isolated components

Joe Armstrong joe@REDACTED
Fri Aug 22 16:26:04 CEST 2003

On Fri, 22 Aug 2003, Laszlo Varga wrote:

> Hello,
> it seems that we are getting understand each other.
> At least we have no clear idea about what Joe want to have.
> Really, it seems that the motivation is to have something
> process based fault tolerancy or robustness or at least stability.
> UBF is also behind the scene, what makes me suspicious.
> Maybe I'm mistaken, but the main point in UBF - I think- the C level,
> the contract. It makes an UBF contract much more strict then an IDL.
> In other words, it specifies the dynamic behaviour while IDLs-are just static.

Yes. APIs are deeply flawed:

Look at this code:

silly() ->
    {ok, H} = file:open("foo.dat", read),

It is stupid - yes, you can't read a line *after* you've closed the file.

Here's the API in some type system:

+type file:open(fileName(), read | write) ->
        {ok, fileHandle()} 
      | {error, string()}.

+type file:read_line(fileHandle()) ->
	{ok, string()}
      | eof.

+type file:close(fileHandle()) ->

+deftype fileName()   = [int()]
+deftype string()     = [int()].
+deftype fileHandle() = pid().

Does this help? - No way.

Add states, like this:

+type start x file:open(fileName(), read | write) ->
           {ok, fileHandle()} x ready
         | {error, string()}  x stop.

+type ready x file:read_line(fileHandle()) ->
	   {ok, string()} x ready
         | eof x atEof.

+type atEof | ready x file:close(fileHandle()) ->
	   true x stop.

+type atEof | ready x file:rewind(fileHandle()) ->
           true x ready

Rule (2) says for example that in the state "ready" you can
evaluate  file:read_line(fileHandle()) and it will return
something of type {ok, string()} and move into state "ready", or it
will return eof and move into state "atEof"

> Is not the THING about building a contract-specified component system?


Contracts and APIs are *almost* equivalent.

  IMHO systems  should be made of  black boxes (ie  my famed components
that I keep blithering on about) - you check the inputs and outputs to
the BBs NOT what goes on at every single function call.

  Inside a BB you might program in assembler (whatever) break all rules of
common-sense etc. But "at the door" - when you pass in or out of the
BB you *must* obey the protocol. Observational equivalence applies.
Any two BBs that behave the same way ARE equivalent.

  The nice thing about doing dynamic checking is we can add non-functional

  for example:

	ready x read_line -> ( {ok, string()} x ready
			       eof x error ) within 5 seconds

  Which is way beyond the state-of-the-art in statically checked systems.

> If it were, i'd like it.

  Then you should like this approach


> Thanks for your time
> Laszlo
> > 
> > Laszlo Varga wrote:
> > > thanks for the "answer". Right, isolation reduces the (possible) complexity,
> > > but is that the motivation for the wrapper project?
> > 
> > Well, *that* is another issue.
> > 
> > I don't know Joe's thoughts on the subject, but my impression is that 
> > it's about coping with failures.
> > If a subroutine crashes, or if it just detects an abnormal condition and 
> > logs it, this is behaviour that punches right through to the top levels 
> > of the application. The "let it crash" philosophy of Erlang says: if a 
> > component fails, let if fail, and don't burden the caller (or service 
> > requester or whatever you name it) with analysis of the crash details, 
> > just tell it that the request failed.
> > The toplevel may be unable to cope with the situation, but then passing 
> > up crash details will introduce lots of coupling just for the rare case 
> > of a crash - the resulting design mess just isn't worth the benefits.
> > 
> > Other languages handle this via exceptions.
> > Eiffel got this right: Eiffel exceptions are unsuitable for passing up 
> > information on a crash (apart from diagnostic information that helps 
> > programmers and debuggers; there's no channel for passing up information 
> > that would help the top-level to analyze the error).
> > Java and C++ got it wrong: they make it all too easy to pass up 
> > information that allows the caller to continue. The net result being 
> > that exceptions create an additional, quite tight coupling between low 
> > and high levels of the system. (It's no good if the top-level of a 
> > system tries to handle an InternetConnectionFailure exception just 
> > because an Internet resource wasn't available ten call levels below it...)
> > 
> > Erlang's idea is to separate the layers of processing into separate 
> > processes, and to let the process crash. The advantage is that this 
> > quite nicely handles any memory leaks that might occur on lower levels 
> > (even garbage-collected languages can leak memory: when calling out into 
> > C, or when accumulating larger and larger structures).
> > I consider it a disadvantage that this interleaves the issues of crash 
> > protection and asynchronous message passing. However, my Erlang 
> > experience is *very* limited, so please consider the latter just an 
> > uninformed opinion.
> > 
> > HTH
> > Jo
> > 

More information about the erlang-questions mailing list