Structs (was RE: Record selectors)

Ulf Wiger etxuwig@REDACTED
Thu Jan 23 13:42:52 CET 2003


I have now read (OK, browsed) the "Reactive Objects and
Functional Programming" thesis, and my understanding is that
the O'Haskell version of the POTS program simply dodged the
issue and pretended either (a) that the response from the
hardware is either always immediate, or (b) control of the
hardware simply could not go wrong.

Moreover, O'Haskell does not allow the programmer to block
or do selective receive. Concurrent Haskell does that, I
believe, but not O'Haskell. The synchronous method
invocation in O'Haskell can only be used in cases where the
other party is guaranteed to return a value immediately.

Thus, it would be an interesting challenge for someone to
rewrite the O'Haskell POTS implementation such that it deals
with the hardware properly (which the Erlang version
actually does.) If I've understood the O'Haskell semantics
correctly, the result will be less than elegant, but I
welcome anyone to prove me wrong.  (:

/Uffe



On Sun, 19 Jan 2003, Sven-Olof Nystr|m wrote:

>Ulf Wiger writes:
> > On Fri, 17 Jan 2003, Sean Hinde wrote:
> >
> > >Well, the comments to their version of the POTS program
> > >from the Erlang book suggest that they see the erlang
> > >ability to "selectively receive" to be merely a way of
> > >avoiding deadlock, and they avoid such nastiness by
> > >statically ensuring that all objects are capable of
> > >receiving all valid messages at all times.
> >
> > I would say that this is a big misunderstanding.
> >
> > Selective receive is not at all about that, and forcing all
> > objects to have to deal with all messages as they come in
> > drastically complicates your state machine programming.
> >
> > Erlang's selective receive -- being able to pattern-match on
> > the entire message queue -- is perhaps not absolutely
> > necessary (even though it is sometimes extremely valuable),
> > but what you need to have for complex state machine
> > programming is (a) the ability to stop and wait for a
> > specific message, and (b) the ability to single out one or a
> > few senders, buffering any other messages until later.
> > (This might also be achieved by having separate channels.)
> > Without this, you end up having to invent quasi states in
> > your code and introducing timing dependencies that will
> > cause nightmares in testing.
> >
> > Let's take the POTS example to illustrate
> >
> > getting_first_digit() ->
> >     receive
> >         {lim, onhook} ->
> >             lim:stop_tone(),
> >             idle();
> >         {lim, {digit, Digit}} ->
> >             lim:stop_tone(),
> >             getting_number(Digit,
> >                            number:analyse(
> >                               Digit,
> >                               number:valid_sequences()));
> >             ...
> >     end.
> >
> > getting_number(Number, {incomplete, ValidSeqs}) ->
> >     receive
> >         {lim, onhook} ->
> >             idle();
> >         {lim, {digit, Digit}} ->
> >             getting_number(10 * Number + Digit,
> >                            number:analyse(
> >                               Digit,
> >                               ValidSeqs));
> >         ...
> >    end.
> >
> > The function lim:stop_tone() actually involves sending a
> > message to the hardware and waiting for a reply (selective
> > receive). If we don't have that ability, we need to handle a
> > stop_tone_reply message in our state machine. Now, what if
> > the next digit comes in before stop_tone_reply? We must now
> > introduce a state (receiving a digit while waiting for
> > stop_tone_reply), and we must process the digit (in most
> > other states, we may happily ignore a pressed digit.)
> >
> > In the specification of the state machine, this is not
> > necessary. It's a product of our programming model. And it's
> > a timing-dependent state, so we will have difficulty
> > provoking it on a real system. We can easily see that there
> > is absolutely no dependency in real life between the
> > response from our hardware and the pressing of a button on
> > the caller's phone. The dependency exists only in our
> > implementation.
> >
> > If we introduce distribution, timing dependencies change,
> > and our code may start breaking because of untested
> > timing-dependent states in our code. The original Erlang
> > state machine is resistant to such problems because it
> > handles events in a logically sound order.
> >
> > _That's_ why selective receive is necessary.
>
>I suppose you have something like this in mind:
>
>(in module lim)
>
>stop_tone() ->
>    <some pid> ! {stop, self()},
>    receive
>        {ok, <some pid>} ->
>            true
>    after ...
>    end.
>
>Implementing this without selective (matching) receive would require
>the ability to create a new channel, something like this:
>
>stop_tone() ->
>    Ch = new_channel()  % Create a new channel
>    <some hardware> ! {stop, Ch},
>    receive(Ch) of      % Read message from channel Ch
>        ok ->
>            true
>    after ...
>    end.
>
>
>As far as I can see, the second solution introduces no new
>complications in the state machine nor any new dependencies. I don't
>know anything about the Haskell solution, but I wouldn't be surprised
>if they are doing something similar.
>
>It would be interesting to see examples where matching receive
>couldn't be replaced by the creation of a temporary channel.
>
>It seems to me that matching receive is just a way to compensate for
>Erlang's inability to create temporary channels...
>
>
>yours,
>
>Sven-Olof Nyström
>
>
>
>
>

-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson Telecom AB, ATM Multiservice Networks




More information about the erlang-questions mailing list