Structs (was RE: Record selectors)

Sven-Olof Nystr|m <>
Sun Jan 19 14:37:24 CET 2003

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()},
        {ok, <some pid>} ->
    after ...

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 ->
    after ...

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...


Sven-Olof Nyström

More information about the erlang-questions mailing list