[erlang-questions] what is the correct syntax to spawm a MFA with no arguments?

Hynek Vychodil vychodil.hynek@REDACTED
Fri May 2 10:52:12 CEST 2008


On Thu, May 1, 2008 at 10:12 PM, Richard Carlsson <richardc@REDACTED> wrote:

> Hynek Vychodil wrote:
>
> > Really? Are you sure? Well, then describe us how long live running
> > server turning around one loop/x function can change code of loop
> > when you don't export loop/x function or some other function called
> > from its loop. Just explain.
> >
>
> Don't mix up two different things: 1) starting a new process, and 2)
> keeping a process running in a loop. What I'm saying is that to start
> a process, there is no problem at all using a fun, or at least, using
> a literal fun that just contains a tail call. The following would
> be a bad idea:
>
>    spawn(fun () -> loop(), io:format("done") end)
>
> because the return address to the io:format call would be pushed on
> the stack (the call to loop() is not tail recursive), and therefore,
> this fun cannot be discarded as long as loop() is running. Not good.
> But for spawn(fun loop/0) or spawn(fun () -> loop() end), there is no
> reference left to the fun, as soon as the call to loop() is entered.


What fool doing it?

>
>
> But _after_ the process has started, you still need the server loop
> to execute a tail call to an exported function, using M:F(...) syntax
> (or apply), in order to support code upgrade. This is a completely
> different thing.
>
> Normally, the starting point for a process is not the actual loop
> function itself, but typically an init function which in its turn
> enters the main loop (which could be an exported function). But even
> if you start the process directly in the loop function, you can use
> another function name for code upgrade.
> For example:
>
>  -export([start/0, upgrade/1]).
>  start() -> spawn(fun loop(0) end).
>  upgrade(S) -> loop(S).
>  loop(S) ->
>    receive
>      X when is_integer(X) -> loop(S+X);
>      upgrade -> ?MODULE:upgrade(S)
>    end.


*** or some other function called from its loop ***  in my question. Nothing
new on the world.

>
>
> But preferably, the user interface (start, stop, etc.) and the server
> loop with its entry point for upgrading should be in separate modules
> to keep the interface cleaner. And in that case you might as well put
> the init function in that other module as well. But you could still
> use spawn(fun moo:init/0) or spawn(fun () -> moo:init(X, Y, Z) end)
> to start the process; there is no need to use spawn/3.
>
> Here are a couple of examples of mistakes you might make if you just
> focus on the spawning of the process. The first one is so easy that
> only beginners make it:
>
>  -export([start/0, loop/1]).
>  start() -> spawn(?MODULE, loop, [0]).
>  loop(S) ->
>    receive
>      X when is_integer(X) -> loop(S+X)
>    end.
>
> (the actual server loop never checks for code upgrades, even though
> it is using an exported function).


If it is not time critical think you can just use

  loop(S) ->
   receive
     X when is_integer(X) -> ?MODULE, loop(S+X)
   end.


>
> The second is one you might make and think that it's not a problem
> because you're only using spawn/3 and fully qualified calls:
>
>  -module(myserver).
>  -export([start/0]).
>  start() -> spawn(myserver_impl, init, [0]).
>
>  -module(myserver_impl).
>  -export([init/1, loop/1]).
>  init(S) -> loop(S), ok.


What fool adding ",ok" in this function? Just remove this stupid thing!


>  loop(S) ->
>    receive
>      X when is_integer(X) -> ?MODULE:loop(S+X)
>    end.
>
> Here, code upgrade will work once, but the second time you try it
> your server process will be killed, because it is still holding on
> to a return pointer to the first version of the module (note that
> the call from init/1 to loop/1 is not a tail call), and Erlang
> only supports two parallel versions of the code, and all processes
> that need even older code will be killed.
>
> There are two main points to understand when it comes to making
> code upgrade work:
>
>  - Your process must regularly (at least each time new code has
>    been loaded) execute a tail-recursive non-local call.
>
>  - You must not leave any return addresses on the process stack
>    that point to old versions of the code, or store funs in the
>    process state that point to old code.
>

Yes of course, but tell something new for me.


> It's the second point that's hardest to grasp, because you need
> a bit of understanding of how the implementation of a functional
> language with tail recursion optimization and garbage collection
> works.
>
> So, it can be quite easy to screw up code upgrade without using any
> funs at all (which most people seem not to worry a lot about), and
> there are really no problems with spawning new processes using
> spawn(fun ...), which many people seem to worry about. Just relax
> and learn to love the bomb. :-)
>
>    /Richard
>



-- 
--Hynek (Pichi) Vychodil
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20080502/a3883930/attachment.htm>


More information about the erlang-questions mailing list