I am not sure how to call a local function in a module so that after the code change the latest version of the code will be used. See the following example:
1 -module(test).
2
3 -export([start/0, call/1]).
4 -export([loop/0, add/1]).
5
6 start() ->
7 register(foo, spawn(test, loop, [])).
8
9 call(X) ->
10 foo ! {self(), X},
11 receive
12 Y -> Y
13 end.
14
15 loop() ->
16 receive
17 {Pid, Z} -> Pid ! add(Z)
18 end,
19 loop().
20
21 add(N) ->
22 N + 1.
The function that will be changed is add/1
. In order to use the latest version of the function, the call of add/1
(line 17) should be fully qualified function call
{Pid, Z} -> Pid ! ?MODULE:add(Z)
.
When I try it, I get this:
1> c(test).
{ok,test}
2> test:start().
true
3> test:call(1).
2
line 22 changed to N + 2
4> c(test).
{ok,test}
5> test:call(1).
3
line 22 changed again to N + 3
6> c(test).
{ok,test}
7> test:call(1).
** exception error: bad argument
in function test:call/1 (test.erl, line 10)
Why do I get this error?
I believe that you need to eventually call the fully qualified version of the loop/0
function instead of the add/1
function in order to load and use the new module. The code loading mechanism is prepared to handle two running versions of a module at once, and your example with N+3
is the third load of the module -- and the first versions is forcibly removed.
Try instead this loop:
15 loop() ->
16 receive
17 {Pid, Z} -> Pid ! add(Z)
18 end,
19 ?MODULE:loop().
I've changed it to reload the newest version on next execution of the loop/0
.
I believe more common is to use a reload
message or similar that will directly call the main loop explicitly, to avoid the overhead of constantly reloading the module on every request.