Mainly I want to know if I can send a function in a message in a distributed Erlang setup.
On Machine 1:
F1 = Fun(
As for anonymous functions, it seems they can be sent and work as expected.
t1@localhost:
(t1@localhost)7> register(shell, self()).
true
(t1@localhost)10> A = me, receive Fun when is_function(Fun) -> Fun(A) end.
hello me you
ok
t2@localhost:
(t2@localhost)11> B = you.
you
(t2@localhost)12> Fn2 = fun (A) -> io:format("hello ~p ~p~n", [A, B]) end.
#Fun<erl_eval.6.54118792>
(t2@localhost)13> {shell, 't1@localhost'} ! Fn2.
I am adding coverage logic to an app built on riak-core, and the merge of results gathered can be tricky if anonymous functions cannot be used in messages.
Also check out riak_kv/src/riak_kv_coverage_filter.erl
riak_kv might be using it to filter
result, I guess.
Here's an interesting article about "passing fun's to other Erlang nodes". To resume it briefly:
[...] As you might know, Erlang distribution works by sending the binary encoding of terms; and so sending a fun is also essentially done by encoding it using erlang:term_to_binary/1; passing the resulting binary to another node, and then decoding it again using erlang:binary_to_term/1.[...] This is pretty obvious for most data types; but how does it work for function objects?
When you encode a fun, what is encoded is just a reference to the function, not the function implementation. [...]
[...]the definition of the function is not passed along; just exactly enough information to recreate the fun at an other node if the module is there.
[...] If the module containing the fun has not yet been loaded, and the target node is running in interactive mode; then the module is attempted loaded using the regular module loading mechanism (contained in the module error_handler); and then it tries to see if a fun with the given id is available in said module. However, this only happens lazily when you try to apply the function.
[...] If you never attempt to apply the function, then nothing bad happens. The fun can be passed to another node (which has the module/fun in question) and then everybody is happy. Maybe the target node has a module loaded of said name, but perhaps in a different version; which would then be very likely to have a different MD5 checksum, then you get the error badfun if you try to apply it.
I would suggest you to read the whole article, cause it's extremely interesting.
You can send any valid Erlang term. Although you have to be careful when sending funs. Any fun referencing a function inside a module needs that module to exist on the target node to work:
(first@host)9> rpc:call(second@host, erlang, apply,
[fun io:format/1, ["Hey!~n"]]).
Hey!
ok
(first@host)10> mymodule:func("Hey!~n").
5
(first@host)11> rpc:call(second@host, erlang, apply,
[fun mymodule:func/1, ["Hey!~n"]]).
{badrpc,{'EXIT',{undef,[{mymodule,func,["Hey!~n"]},
{rpc,'-handle_call_call/6-fun-0-',5}]}}}
In this example, io
exists on both nodes and it works to send a function from io
as a fun. However, mymodule
exists only on the first node and the fun generates an undef
exception when called on the other node.