Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang code_change and local function call

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?

like image 871
juro Avatar asked Dec 30 '25 00:12

juro


1 Answers

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.

like image 176
sarnold Avatar answered Dec 31 '25 22:12

sarnold