[erlang-questions] Sending fun/1 over the network and apply/2 failure

zxq9 <>
Mon Jul 25 05:33:15 CEST 2016


On 2016年7月25日 月曜日 00:09:36 Sid Muller wrote:
> Hi everyone,
> 
> I am having an issue that I don't really understand why it's happening.
> 
> In the shell I create a fun on one node:
> Fa = fun(A)->A end.
> #Fun<erl_eval.6.50752066>
> 
> Then call term_to_binary()
> 
> which gives me the following:

... snip ...

> I get:
> #Fun<erl_eval.6.50752066>
> 
> And then I call:
> apply(Fa, ["Param"]).
> 
> And the code works fine, as long as I do that on the console.
> 
> But if I do that in erlang code and send the binary over the network, and I print it to make sure that it's the same as the binary above. Then when I call apply it fails. I get this:
> 
> Error in process <0.5040.1> with exit value:
> {{badfun,#Fun<erl_eval.6.50752066>}, ....
> 
> 
> I am completely lost why cut and paste works from the console but from erlang code it fails, even though everything is the same, both binary and the parameters I'm passing to apply/2.
> 
> What am I missing, does anyone have any pointers? I find it very strange...

Funs are not portable between nodes the way other values are. I'm fuzzy on
the implementation details, but they basically work as a reference to a
locally stored fun + whatever data is bound within that particular fun.

(I'm mildly curious how this works in the shell... anyone care to explain it?)

When you try to execute this fun reference somewhere else it cannot be
dereferenced because the underlying fun was never defined on the other node.

There is a proposal for "portable funs":
http://www.erlang.org/erlang-enhancement-proposals/eep-0015.html

But its still a low priority.


An aside on funs in Erlang...

It is rare to see long-lived funs (and in a system where you expect hot
upgrades this would be unwise anyway -- because you would have this legacy
fun floating around for a long time). While it is pretty common (and super
convenient) to define protocols over TCP as term_to_binary/binary_to_term,
it is *still* important to write the socket handlers in a way that they
"implement a protocol" instead of execute raw values.

In Erlang I find that lambdas are useful mostly as a way of closing over
some ongoing state to curry out the parts of an operation that don't fit
cleanly into a list operation -- or especially to write dispatch functions
as funs so that each dispatched call can be to any function of any arity
instead of writing a ton of wrappers. Its not like guile where I would feel
comfortable writing a system init function that composes a system's start
function and then kicks the whole thing off as one giant lambda.

-Craig


More information about the erlang-questions mailing list