Selective receive (RE: Structs (was RE: Record selectors))

Ulf Wiger <>
Mon Jan 20 17:12:31 CET 2003


On Mon, 20 Jan 2003, Sven-Olof Nystr|m wrote:

>Ulf Wiger writes:

> > I think a single message queue and pattern matching go well
> > in hand with state-oriented programming. Again, the POTS
> > example:
> >
> > speech(OtherPid) ->
> >     receive
> >         {lim, onhook} ->
> >             lim:disconnect_from(OtherPid),
> >             OtherPid ! {self(), cancel},
> >             idle();
> >         {lim, {digit, _Digit}} ->
> >             speech(OtherPid);
> >         {OtherPid, cancel} ->
> >             wait_on_hook(false);
> >         {Pid, request_connection} ->
> >             Pid ! {self(), reject},
> >             speech(OtherPid);
> >         Other ->
> >             speech(OtherPid)
> >     end.
> >
> > Here, we react to messages from 4 different senders
> > (consuming and ignoring any message from anyone else). One
> > could of course imagine an equally concise syntax that
> > scanned separate channels, pattern-matching over them,
> > blocking if desired and necessary.
>
>Yes. This could be written with a receive operation that
>simply grabs the next message in the mailbox + a case
>statement.

Yes, because the receive statement in this case has a
catch-all branch, which means that it will always consume
the first message that comes along.

The following is a state from a prototype ATM call control
state machine:

loop_setup_sent(HcData, VolData) ->
    receive
        {setupB, PidB, MsgType, IEs, HcIdB, ResourcesB} ->
            %%from bside
            case MsgType of
                ?CONNECT ->
                    connect(...);
                ?RELEASE ->
                   placeholder(?PHARGS);
                ?ALERTING ->
                    placeholder(?PHARGS);
                _ ->
                    placeholder(?PHARGS)
            end;
        {from_dispatch, HcIdAfromA, MessageType, Message} ->
            %%from sigport (Aside)
            case {uniccLibrary:tokenize_sort(Message),
                  MessageType} of
                {{ok, IEs}, ?CONNECT_ACKNOWLEDGE} ->
                    connect_ack();
                {{ok, IEs}, ?RELEASE} ->
                    placeholder(?PHARGS);
                {{ok, IEs}, _} ->
                    placeholder(?PHARGS);
                {{error, Cause}, _} ->
                    placeholder(?PHARGS)
            end
    end


This is slightly more difficult to rewrite as a case
statement, because the code is doing a blocking wait on two
"channels" simultaneously. One may assume that in the normal
case, the program will consume the first message on any of
the channels which it is currently monitoring. Then, this
amounts to a blocking poll() on a subset of open channels
followed by a case. I have trouble finding example code
where this would not be adequate.


>Matching receive is a rather strange construct. If
>arbitrary expressions were allowed in guards, it would be
>possible to write a receive that counted the messages in a
>mailbox. Unlike case statements, there is no way to
>translate a receive into simpler things (this affected the
>design of Core Erlang). As far as I know, no other
>programming language has anything similar.

This need not be an argument against matchin receive per se,
as few other languages have a track record in concurrent
programming that matches that of Erlang... (:

But I cannot argue that matching receive is indispensable as
long as I cannot find a single good example where one
couldn't do equally well (more or less) with multiple
channels. (:


/Uffe
-- 
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