Structs (was RE: Record selectors)
Sven-Olof Nystr|m
svenolof@REDACTED
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()},
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
More information about the erlang-questions
mailing list