[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