Thanks for very nice example.<br><br><div class="gmail_quote">On Mon, May 26, 2008 at 4:54 AM, Richard A. O'Keefe <<a href="mailto:ok@cs.otago.ac.nz">ok@cs.otago.ac.nz</a>> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
On 23 May 2008, at 11:05 pm, Mats Cronqvist wrote:<br>
<br>
Hooray!  Evidence!<br>
<div><div></div><div class="Wj3C7c">>  let me assure you that there are major telecom equipment vendors<br>
> whose<br>
> code bases would benefit greatly from this syntax.<br>
>  although i (no longer) has access to that code, the pattern appears<br>
> quite often in event-driven programming. here's a very small example<br>
> from a simple GUI application;<br>
><br>
> loop(St) -><br>
>    receive<br>
>    %% user deleted top window<br>
>    {?MODULE,{signal,{window1,_}}}       -> quit();<br>
>    %% user selected quit menu item<br>
>    {?MODULE,{signal,{quit1,_}}}       -> quit();<br>
>    %% user selected  connect menu item<br>
>    {?MODULE,{signal,{connect,_}}}       -> loop(conn(St));<br>
>    %% user selected  disconnect menu item<br>
>    {?MODULE,{signal,{disconnect,_}}} -> loop(disc(St));<br>
>    %% user selected about menu item<br>
>    {?MODULE,{signal,{about1,_}}}       -> loop(show_about(St));<br>
>    %% user clicked ok in about dialog<br>
>    {?MODULE,{signal,{dialogb,_}}}      -> loop(hide_about(St));<br>
>    %% user deleted about dialog<br>
>    {?MODULE,{signal,{dialog1,_}}}       -> loop(hide_about(St));<br>
>    %% we got data from the top_top process<br>
>    {data,Data}                       -> loop(update(St,Data));<br>
>    %% quit from the erlang shell<br>
>    quit                              -> quit();<br>
>    %% log other signals<br>
>    X                                 -> io:fwrite("got ~p~n",<br>
> [X]),loop(St)<br>
>    end.<br>
><br>
<br>
</div></div>Let me start by making two changes to that code.<br>
The first is to indent it, so that I can read it.<br>
The second is to group together things with the same body.<br>
<br>
     loop(St) -><br>
         receive<br>
            quit -><br>
                %% quit from the Erlang shell<br>
                quit()<br>
          ; {?MODULE,{signal,{window1,_}}} -><br>
                %% User deleted top window.<br>
                quit()<br>
          ; {?MODULE,{signal,{quit1,_}}} -><br>
                %% User selected 'Quit' menu item.<br>
                quit()<br>
          ; {?MODULE,{signal,{connect,_}}} -><br>
                %% User selected 'Connect' menu item.<br>
                loop(conn(St))<br>
          ; {?MODULE,{signal,{disconnect,_}}} -><br>
                %% User selected 'Disconnect' menu item.<br>
                loop(disc(St))<br>
          ; {?MODULE,{signal,{about1,_}}} -><br>
                %% User selected 'About' menu item.<br>
                loop(show_about(St))<br>
          ; {?MODULE,{signal,{dialogb,_}}} -><br>
                %% User clicked 'OK' in "about" dialogue.<br>
                loop(hide_about(St))<br>
          ; {?MODULE,{signal,{dialog1,_}}} -><br>
                %% User deleted "about" dialogue.<br>
          ; {data,Data} -><br>
                %% We got data from the top_top process.<br>
                loop(update(St, Data))<br>
          ; X -><br>
                %% Log other signals.<br>
<div class="Ih2E3d">                io:fwrite("got ~p~n", [X]),<br>
                loop(St)<br>
        end.<br>
<br>
</div>In this case, it matters that *every* message is to be received and<br>
acted on.  That means that we can once again use the factorisation<br>
technique.<br>
<br>
     loop(State) -><br>
        receive<br>
            Message -><br>
                loop(State, classify(Message))<br>
        end.<br>
<br>
     classify(quit)                             -> quit;<br>
     classify({?MODULE,{signal,{window1,_}}})   -> quit;<br>
     classify({?MODULE,{signal,{quit1,_}}})     -> quit;<br>
     classify({?MODULE,{signal,{connect,_}}})   -> connect;<br>
     classify({?MODULE,{signal,{disconnect,_}}})        -> disconnect;<br>
     classify({?MODULE,{signal,{about1,_}}})    -> show_about;<br>
     classify({?MODULE,{signal,{dialog1,_}}})   -> hide_about;<br>
     classify({?MODULE,{signal,{dialogb,_}}})   -> hide_about;<br>
     classify({data,Data})                      -> {data,Data};<br>
     classify(X)                                        -> {error,X}.<br>
<br>
     loop(_, quit) -><br>
        quit();<br>
     loop(State, connect) -><br>
        loop(conn(State));<br>
     loop(State, disconnect) -><br>
        loop(disc(State));<br>
     loop(State, show_about) -><br>
        loop(show_about(State));<br>
     loop(State, hide_about) -><br>
        loop(hide_about(State));<br>
     loop(State, {data,Data}) -><br>
        loop(update(State, Data));<br>
     loop(State, {error,X}) -><br>
<div class="Ih2E3d">        io:fwrite("got ~p~n", [X]),<br>
</div>        loop(State).<br>
<br>
I like this because it makes a clean separation between<br>
"what are the actions" and "what are the names for the actions".<br>
<br>
Of course you can in-line this.  Just as we can have<br>
case/case, we can have case/receive, getting<br>
<br>
     loop(State) -><br>
        case receive<br>
                 quit                              -> quit<br>
               ; {?MODULE,{signal,{window1,_}}}    -> quit<br>
               ; {?MODULE,{signal,{quit1,_}}}      -> quit<br>
               ; {?MODULE,{signal,{connect,_}}}    -> connect<br>
               ; {?MODULE,{signal,{disconnect,_}}} -> disconnect<br>
               ; {?MODULE,{signal,{about1,_}}}     -> show_about<br>
               ; {?MODULE,{signal,{dialog1,_}}}    -> hide_about<br>
               ; {?MODULE,{signal,{dialogb,_}}}    -> hide_about<br>
               ; {data,Data}                       -> {data,Data}<br>
               ; X                                 -> {error,X}<br>
             end<br>
          of quit       -> quit()<br>
           ; connect    -> loop(conn(State))<br>
           ; disconnect -> loop(disc(State))<br>
           ; show_about -> loop(show_about(State))<br>
           ; hide_about -> loop(hide_about(State))<br>
           ; {data,D}   -> loop(update(State, D))<br>
           ; {error,X}  -> io:fwrite("got ~p~n", [X]),<br>
                           loop(State)<br>
        end.<br>
<br>
Now my first reaction on seeing a whole raft of {?MODULE,{signal,<br>
{Foo,_}}}<br>
patterns was "this is too hard for me to read".  I would be trying to<br>
simplify the protocol.  Separating the receive protocol from the action<br>
selection makes this kind of maintenance easier.  Inlining means that<br>
the versions with separate functions and with nested case/receive are<br>
operationally equivalent.  A few hacks in the compiler could produce<br>
essentially the same code as the original version, although I doubt that<br>
it would be worth bothering.<br>
<br>
Tastes vary.  To me, what we can write now in Erlang as it stands,<br>
separating "what are the actions" from "what are the names for the<br>
actions",<br>
is easier to read and understand than anything using multiple patterns<br>
would be, not because multiple patterns are a bad idea as such, but<br>
because<br>
combining multiple *complex* patterns into a single match makes the code<br>
harder to read.  Multiple *simple* patterns might make for a more<br>
interesting example.<br>
<div class="Ih2E3d"><br>
--<br>
"I don't want to discuss evidence." -- Richard Dawkins, in an<br>
interview with Rupert Sheldrake.  (Fortean times 232, p55.)<br>
<br>
<br>
<br>
<br>
<br>
<br>
_______________________________________________<br>
</div><div><div></div><div class="Wj3C7c">erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
<a href="http://www.erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://www.erlang.org/mailman/listinfo/erlang-questions</a><br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>--Hynek (Pichi) Vychodil