Search code examples
erlangspawn

Erlang - Spawn MFA vs Spawn Fun


I have been trying to work with Programming Erlang , Version 2 ( Joe Armstrong's book). I am trying to solve the first problem in the Chap 13.

As a solution to the problem - I came up with this -

-module(errorhandle1).
-export([my_spawn/3,loop/1,test_func/0]).

my_spawn(Mod,Fun,Args) -> 
   %SpawnedPidRef = myspawn_helper(Mod,Fun,Args),
   %spawn(?MODULE , loop , [myspawn_helper(Mod,Fun,Args)]).
   spawn(fun() -> loop(myspawn_helper(Mod,Fun,Args)) end).

myspawn_helper(Mod,Fun,Args) ->
   statistics(wall_clock),
   spawn_monitor(Mod,Fun,Args).

loop({SpPid,SpRef}) ->
   io:format("Created Pid is : ~p~n",[SpPid]),
   receive
      {makeError,Msg} -> 
          SpPid ! Msg,
          loop({SpPid,SpRef});
      {'DOWN',SpRef, process,SpPid,Why} ->
          {_, Time1} = statistics(wall_clock),
            io:format("Down"),
            io:format("Process spawn time = ~p microsecond ~n",[Time1])
end.

test_func() ->
    receive
        X -> 
           list_to_atom(X)
    end.

The above code works and produces the desired output (first step is to solve the problem). Then I commented the line and came up with the following program , which is exactly same as the above one but , I use spawn/3 function instead of a spawn/1 and I dont seem to get the desired output.

-module(errorhandle1).
-export([my_spawn/3,loop/1,test_func/0]).

my_spawn(Mod,Fun,Args) -> 
   %SpawnedPidRef = myspawn_helper(Mod,Fun,Args),
   spawn(?MODULE , loop , [myspawn_helper(Mod,Fun,Args)]).
   %spawn(fun() -> loop(myspawn_helper(Mod,Fun,Args)) end).

myspawn_helper(Mod,Fun,Args) ->
   statistics(wall_clock),
   spawn_monitor(Mod,Fun,Args).

loop({SpPid,SpRef}) ->
   io:format("Created Pid is : ~p~n",[SpPid]),
   receive
      {makeError,Msg} -> 
          SpPid ! Msg,
          loop({SpPid,SpRef});
      {'DOWN',SpRef, process,SpPid,Why} ->
          {_, Time1} = statistics(wall_clock),
            io:format("Down"),
            io:format("Process spawn time = ~p microsecond ~n",[Time1])
end.

test_func() ->
    receive
        X -> 
           list_to_atom(X)
    end.

Steps to execute the above module: c(errorhandle1). Pid = errorhandle1:my_spawn(errorhandle1,test_func,[]). Pid ! {makeError,test}.

Can some please help me with my understanding of the usage of spawn/3 and spawn/1 ?

Thanks, Sathish.


Solution

  • spawn(fun() -> loop(myspawn_helper(Mod,Fun,Args)) end).
    

    is not an equivalent of

    spawn(?MODULE , loop , [myspawn_helper(Mod,Fun,Args)]).
    

    in the second case [myspawn_helper(Mod,Fun,Args)] is a parameter of function spawn/3. The value of a parameter is evaluated before a function call. It means the call myspawn_helper(Mod,Fun,Args) is made before the call to the spawn/3 outside of a new process in the original one. You can see it as this code

    SpawnedPidRef = myspawn_helper(Mod,Fun,Args),
    spawn(?MODULE , loop , [SpawnedPidRef]).
    

    the equivalent with spawn/1 would look like

    SpawnedPidRef = myspawn_helper(Mod,Fun,Args),
    spawn(fun() -> loop(SpawnedPidRef) end).
    

    Now you can see the difference. Only loop(SpawnedPidRef) is actually done inside a new process. But in your first version you perform loop(myspawn_helper(Mod,Fun,Args)) in a new process. You can see it like

    spawn(fun() ->
            SpawnedPidRef = myspawn_helper(Mod,Fun,Args),
            loop(SpawnedPidRef)
        end).
    

    which is very different code. (See the last two blocks. The last one is you first version and other one is your second version.)