[erlang-questions] funs and code loading

Attila Babo <>
Tue Jan 15 20:59:52 CET 2008


Let's simplify your example to mark the difference:

loop() ->
    A = fun f/0,
    io:fwrite("~p ~p ~p~n", [A(), f(), ?MODULE:f()]),
    timer:sleep(3000),
    loop().

This will print "2 1 2" after changing VERSION from 1 to 2, because
the A = fun f/0 binding is dynamic at the function scope in run time,
while the call to f as f() at the next line is local and bound at
compile time. Recursion is through our original loop function, so f()
remains the same, while at each call A binds to the latest code. If we
do recursion at the last line with a ?MODULE:loop() global call, then
the local call of f() will bound to the actual code version and the
function will print "2 2 2" after code reloading.

In your original example the loop calls itself as loop(E, F, G, H),
here all of these variables goes out of scope and bind again to the
latest version at that time. This has the same effect as
    loop(fun ?MODULE:f/0, fun() -> f() end, fun f/0, fun() -> ?VERSION end).
As we are calling the original module's loop function the static value
of VERSION remains the same while f itself changes, so these print "2
2 2 1" after code change.

It has an interesting side effect if we do recursion with a
?MODULE:loop call. Here the first function will print "2 2 2 1" after
code change, as the original module's version, but after that this
will switch to our latest code so the output changes to "2 2 2 2".

As we can have only two versions of the same module after our second
change code server purges out the original module, so this example has
a limited use, but good for demonstration. I just hope that all these
make sense and I'm not making ideology for a bug:-). Please correct me
if I was wrong!

Attila

-----------

-module(reload).
-export([go/0, f/0, c/0]).
-export([loop/0]).
-define(VERSION, 1).
-vsn(version_1).

go() ->
  spawn(fun() -> loop() end).

f() ->
  ?VERSION.

loop() ->
  A = fun f/0,
  io:fwrite("~p ~p ~p~n", [A(), f(), ?MODULE:f()]),
  timer:sleep(3000),
  loop().

c() ->
  code:purge(?MODULE),
  code:load_abs(?MODULE).



More information about the erlang-questions mailing list