Sunday, October 21, 2012

Problem 8.11 - a pragmatic touch

When I posted my solution to the problem how you can safely register an atom as a process handler, I was into the registration process itself. As it happens, if you want to USE that registered process, the other code I was referring to is simply incorrect: you will not be able to use the atoms you registered. Thanks to Roach for pointing that out.
The following is a complete module to test my approach. The messaging was slightly changed.
First, the sample session:
1> c(prob8101pragmatic).
{ok,prob8101}
2> prob8101pragmatic:unittest().
[true,true,true,true,true,true,true,true]
And now the module itself:
-module(prob8101pragmatic).
-export([start/2,init_registrar/0, server/2, client/2, unittest/0]).

init_registrar() ->
   register(registrar,spawn(fun() -> loop() end)).

loop() ->
receive
  {register,Atom,Fun,From} ->
     case whereis(Atom) of
        undefined ->
           register(Atom,spawn(Fun)),
           From!{registered_ok,whereis(Atom)},
           loop();
        _Otherwise ->
           From!{already_registered,whereis(Atom)},
           loop()
     end;
   {stop, From} ->
       From!{stopped,self()}
end.

server(Atom,F) ->
    receive {enough,From} ->  
     From!{Atom, exited},
     ok;
            {X,From}      ->  
     From!{Atom, F(X)},
     server(Atom, F)
    end.

client(Atom, Param) ->
    Atom!{Param,self()},
    receive {Atom,Y} ->  
       % io:format("received from ~p: ~p~n", [Atom,Y]),
       Y
    end.
    
start(AnAtom, Fun) ->
   registrar ! {register, AnAtom, fun() -> server(AnAtom, Fun) end, self()},
   receive
     {Result,Newid} -> {Result,Newid}
   end.

stop_registry() ->
   registrar ! {stop, self()},
   receive
     {Result,_Rid} -> Result
   end.

unittest() -> 
    Sq = fun(X) -> X * X end,
    Qb = fun(X) -> X * X * X end,
    init_registrar(),
    {R_OK,_} = start(square, Sq),
    {R_NO,_} = start(square, Sq),
    {R_OK,_} = start(cube, Qb),
    TwentyFive = client(square, 5),
    SixtyFour  = client(square, 8),
    Nine       = client(cube, 3),
    C125       = client(cube, 5),
    Exited     = client(square, enough),
    Exited     = client(cube,   enough),
    Stopped    = stop_registry(),
    [   R_OK       == registered_ok,
        R_NO       == already_registered,
        TwentyFive == 25,
        SixtyFour  == 64,
        Nine       == 27,
        C125       == 125,
        Exited     == exited,
        Stopped    == stopped
        ].