Sharas
Sharas

Reputation: 905

What is the point of Spawn(Node, Fun) on erlang, if Node has to have the same module loadable as a client node?

Why create illusion that you are sending a Fun to remote node to execute in a new process? If client node has to have same module loadable with the Fun defined as a server node anyway. Why not only spawn(Node, M, F, A) then, which makes it clear that you are sending a definition of a function call, not Fun itself.

Upvotes: 6

Views: 887

Answers (2)

Pascal
Pascal

Reputation: 14042

The example below shows that the remote node can execute a code that was never loaded on it, even a call to an anonymous function that was defined on the caller node:

on node titi

Erlang/OTP 19 [erts-8.0] [64-bit] [smp:4:4] [async-threads:10]

Eshell V8.0  (abort with ^G)
(titi@XXXXXXXX)1> net_adm:ping(toto@XXXXXXXX).
pong
(titi@XXXXXXXX)2> F = fun F(X) -> receive {plus,N} -> F(X+N); get -> io:format("state is ~p~n",[X]), F(X); stop -> bye end end. 
#Fun<erl_eval.30.52032458>
(titi@XXXXXXXX)3> G = fun() -> register(server,self()), F(0) end.
#Fun<erl_eval.20.52032458>
(titi@XXXXXXXX)4> spawn(toto@XXXXXXXX,G).
<7039.67.0>
state is 0           
state is 5           
state is 10          
(titi@XXXXXXXX)5> 

on node toto

Erlang/OTP 19 [erts-8.0] [64-bit] [smp:4:4] [async-threads:10]

Eshell V8.0  (abort with ^G)
(toto@XXXXXXXX)1> server ! get. % will print state is 0
get
(toto@XXXXXXXX)2> server ! {plus,5}. % new state = 5
{plus,5}
(toto@XXXXXXXX)3> server ! get. % will print state is 5    
get
(toto@XXXXXXXX)4> server ! {plus,5}. % new state = 10
{plus,5}
(toto@XXXXXXXX)5> server ! get. % will print state is 10     
get
(toto@XXXXXXXX)6> server ! stop. % ends the server process    
stop
(toto@XXXXXXXX)7> server ! get. % message will fail
** exception error: bad argument
     in operator  !/2
        called as server ! get
(toto@XXXXXXXX)8> 

I also checked that if you replace the code {plus,N} -> F(X+N); by {plus,N} -> F(maps:put(X,X+N,maps:new())); which is calling a module not loaded by the shell at start, it works fine as well.

Edit

Read the comments, it seems that doing the test in the shell is not the right way, 2 conclusions though:

  • do not rely on the shell only to make verifications,
  • there should be a way to execute on the remote node a code that was only known on the caller node since the shell can do it...

Upvotes: 2

Lol4t0
Lol4t0

Reputation: 12557

Let's consider two possible cases

Functions referring to module functions

Fun = fun file:getcwd/0,
erlang:spawn(Node, Fun). 

In this case Fun indeed should be loadable at the remote side.

Anonymous functions

Fun = fun() -> io:format("My node is ~p~n", [node()]) end,
erlang:spawn(Node, Fun). 

They are callable also.

Summarizing

While there some limitations implied to a function, that can be spwaned remotely, this form is still suitable and can be dropped, because then second case would become impossible

Also

Some misconceptions might go from this article

Actually, if you run erlang:fun_info for anonymous function, you'll see, that it provides implementation in a form of AST

(b@lol4t0-home)21> rp(erlang:fun_info(fun() -> io:format("My node is ~p~n", [node()]) end)). 
[{pid,<0.96.0>},
 {module,erl_eval},
 {new_index,20},
 {new_uniq,<<99,62,121,82,122,95,246,237,63,72,118,40,4,
             25,16,50>>},
 {index,20},
 {uniq,52032458},
 {name,'-expr/5-fun-3-'},
 {arity,0},
 {env,[{[],
        {eval,#Fun<shell.21.31625193>},
        {value,#Fun<shell.5.31625193>},
        [{clause,1,[],[],
                 [{call,1,
                        {remote,1,{atom,1,io},{atom,1,format}},
                        [{string,1,"My node is ~p~n"},
                         {cons,1,{call,1,{atom,1,node},[]},{nil,1}}]}]}]}]},
 {type,local}]

Upvotes: 6

Related Questions