A = 2, B = 3, F = fun() -> A + B end,
R = gen_server:call({global, et}, F).
and R will contain 5.
where
module et contains the function
handle_call(F, _From, State) when is_function(F) ->
{reply, F(), State}.
Question: is it safe to assume that A, B and possibly other variables will contain the values assigned to them before the definition of the local function?
During compilation this closure will be âliftedâ, what means that it will be compiled as a function of A and B arguments. And when you instantiate this closure (that is when F = fun() ... expression is executed) it will create a kind of âtupleâ consisting of values of A and B and also a reference to the lifted function.
When you send this closure to other process on local node (that is during this gen_server:call), it will basically just copy this tuple to the other process, copying it values and copying reference to the function. So when you execute this closure in other process, it will be executed on copied values of A and B. That means that on the moment of this closure executing, values in the original process may already be garbage collected, but this garbage collection wonât affect the result since execution of closure is happening with copied context.
If the {global, et} process is on other node, runtime will also copy the closure in some form which can be interpreted in runtime, but it wonât copy the modules and other local functions this closure calls, so that means that
A = 2, B = 3, F = fun() -> some_module:some_function(A) + B end,
R = gen_server:call({global, et}, F).
can fail if node where the {global, et} process is at does not contain module some_module or contains this module but without the some_function. And in case some_module:some_function is present on this node, but implementation is different, result will also be different.
Thatâs why it is advised not to send closures between nodes, though runtime is capable of doing this
There is no assignment, only binding. And in the sense you may be thinking of, there are no variables, only names for values. The function F has no access to âvariablesâ A and B, the data structure that is bound to F contains the values the were bound to A and B and the code of F gets A and B from that data structure. The environment that originally contained A and B may have disappeared long ago when F is called, so referring to that environment would be a bad idea.
In programming languages like Algol 60, Pascal, and GNU C, a nested function can be called and passed around as long as the environment where it was created is still active, but it cannot be used once that environment is exited. That being so, a nested function can refer to non-local variables in the original homes. In functional programming languages like SML and Erlang, âvariablesâ are just names for values and nested functions can be freely used long after the environment they were defined in has joined its ancestors. That being so, a nested function in such languages cannot get the values of non-local variables from their original homes.
In your example, the A inside F and the A outside F, should they have memory addresses, will not have the same address. They just have the same value.
so is it correct if i summarize as follows: âvariablesâ are always passed âby valueâ and never âby referenceâ. as long as the function will be executed on the same node, it is safe if it calls any functions in other modules. however, if the function is executed on a different node, predictable results cannot be expected if it calls functions from any non-standard modules.
There are no variables in the Fortran/C/Pascal/Java/C# sense.
There is nothing that pass-by-reference could refer to, and if there were, pass by reference
would be useless since once an identifier is bound to a value, it cannot be rebound.
It doesnât matter whether a function is executed on the same node or not, if you send a
closure from one node to another, the values will be completely intact when they arrive
(even if the original node is switched off, melted down, formed into cuspidors, and
sent to Mars). The question is whether the function finds the same versions of the
modules it calls already loaded, standard or non-standard. References to processes in
the original node will still refer to those processes on that node.
please excuse me if i didnât choose the correct terminology. with âby valueâ and âby referenceâ (please note the quotation marks) i wanted to imply a certain analogy to c, c++. itâs just a bit difficult for me to forget my years of experience with c, c++, âŠ