<br><br><div class="gmail_quote">On Thu, May 1, 2008 at 10:12 PM, Richard Carlsson <<a href="mailto:richardc@it.uu.se">richardc@it.uu.se</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;">
<div class="Ih2E3d">Hynek Vychodil wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Really? Are you sure? Well, then describe us how long live running server turning around one loop/x function can change code of loop<br>
when you don't export loop/x function or some other function called<br>
from its loop. Just explain.<br>
Don't mix up two different things: 1) starting a new process, and 2)<br>
keeping a process running in a loop. What I'm saying is that to start<br>
a process, there is no problem at all using a fun, or at least, using<br>
a literal fun that just contains a tail call. The following would<br>
be a bad idea:<br>
    spawn(fun () -> loop(), io:format("done") end)<br>
because the return address to the io:format call would be pushed on<br>
the stack (the call to loop() is not tail recursive), and therefore,<br>
this fun cannot be discarded as long as loop() is running. Not good.<br>
But for spawn(fun loop/0) or spawn(fun () -> loop() end), there is no<br>
reference left to the fun, as soon as the call to loop() is entered.</blockquote><div><br>What fool doing it?<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
But _after_ the process has started, you still need the server loop<br>
to execute a tail call to an exported function, using M:F(...) syntax<br>
(or apply), in order to support code upgrade. This is a completely<br>
different thing.<br>
Normally, the starting point for a process is not the actual loop<br>
function itself, but typically an init function which in its turn<br>
enters the main loop (which could be an exported function). But even<br>
if you start the process directly in the loop function, you can use<br>
another function name for code upgrade.<br>
For example:<br>
  -export([start/0, upgrade/1]).<br>
  start() -> spawn(fun loop(0) end).<br>
  upgrade(S) -> loop(S).<br>
  loop(S) -><br>
      X when is_integer(X) -> loop(S+X);<br>
      upgrade -> ?MODULE:upgrade(S)<br>
    end.</blockquote><div><br>*** or some other function called from its loop ***  in my question. Nothing new on the world.<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
But preferably, the user interface (start, stop, etc.) and the server<br>
loop with its entry point for upgrading should be in separate modules<br>
to keep the interface cleaner. And in that case you might as well put<br>
the init function in that other module as well. But you could still<br>
use spawn(fun moo:init/0) or spawn(fun () -> moo:init(X, Y, Z) end)<br>
to start the process; there is no need to use spawn/3.<br>
Here are a couple of examples of mistakes you might make if you just<br>
focus on the spawning of the process. The first one is so easy that<br>
only beginners make it:<br>
  -export([start/0, loop/1]).<br>
  start() -> spawn(?MODULE, loop, [0]).<br>
  loop(S) -><br>
      X when is_integer(X) -> loop(S+X)<br>
(the actual server loop never checks for code upgrades, even though<br>
it is using an exported function).</blockquote><div><br>If it is not time critical think you can just use <br><br> 
 loop(S) -><br>
      X when is_integer(X) -> ?MODULE, loop(S+X)<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
The second is one you might make and think that it's not a problem<br>
because you're only using spawn/3 and fully qualified calls:<br>
  start() -> spawn(myserver_impl, init, [0]).<br>
  -export([init/1, loop/1]).<br>
  init(S) -> loop(S), ok.</blockquote><div><br>What fool adding ",ok" in this function? Just remove this stupid thing!<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
  loop(S) -><br>
      X when is_integer(X) -> ?MODULE:loop(S+X)<br>
Here, code upgrade will work once, but the second time you try it<br>
your server process will be killed, because it is still holding on<br>
to a return pointer to the first version of the module (note that<br>
the call from init/1 to loop/1 is not a tail call), and Erlang<br>
only supports two parallel versions of the code, and all processes<br>
that need even older code will be killed.<br>
There are two main points to understand when it comes to making<br>
code upgrade work:<br>
  - Your process must regularly (at least each time new code has<br>
    been loaded) execute a tail-recursive non-local call.<br>
  - You must not leave any return addresses on the process stack<br>
    that point to old versions of the code, or store funs in the<br>
    process state that point to old code.<br>
</blockquote><div><br>Yes of course, but tell something new for me.<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
It's the second point that's hardest to grasp, because you need<br>
a bit of understanding of how the implementation of a functional<br>
language with tail recursion optimization and garbage collection<br>
So, it can be quite easy to screw up code upgrade without using any<br>
funs at all (which most people seem not to worry a lot about), and<br>
there are really no problems with spawning new processes using<br>
spawn(fun ...), which many people seem to worry about. Just relax<br>
and learn to love the bomb. :-)<br><font color="#888888">
</font></blockquote></div><br><br clear="all"><br>-- <br>--Hynek (Pichi) Vychodil