What kind of types can be sent on an Erlang message?
Asked Answered
O

3

8

Mainly I want to know if I can send a function in a message in a distributed Erlang setup.

On Machine 1:

F1 = Fun()-> hey end,

gen_server:call(on_other_machine,F1)

On Machine 2:

handler_call(Function,From,State) ->
{reply,Function(),State)

Does it make sense?

Olodort answered 24/5, 2011 at 13:29 Comment(0)
U
8

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.

Urata answered 24/5, 2011 at 14:21 Comment(0)
C
6

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.

Cod answered 24/5, 2011 at 13:52 Comment(2)
What about anonymous functions?Olodort
If by that you mean anonymous funs, it has the same problem. I.e. the module where it is defined has to exist on the remote node.Gripsack
M
4

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.

Mecke answered 1/4, 2016 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.