Doubt about funs

Martin Bjorklund mbj@REDACTED
Tue Feb 20 22:49:23 CET 2001


Richard Carlsson <richardc@REDACTED> wrote:
> 
> > "We can also refer a function defined in a different module with
> > the following syntax:
> > 
> > F = {Module,FunctionName}  "
> 
> Yes, it is true that you can (still) use tuples {Module, FunctionName} in
> this manner, but it is a relic of early Erlang implementations and I
> strongly recommend that they are not used in new code.
> If you need to pass
> around a functional value to call a particular function in a particular
> module, the following is much better:
> 
> 	F = fun (X1, ..., Xn) -> m:f(X1, ..., Xn) end

I strongly disagree.  These two constructs behave very different!
Using F in the former construct is an external apply, which means that
the latest version of the code gets called.  Using F in the latter, on
the other hand, is a call to the function defined in the version of
the module that was there when F was constructed.  Thus, if a new
version of the module (where the fun was defined) is loaded, and you
try to use F, you'll using the old version.  If yet another version of
the module is loaded, F is invalid, and the process is killed.

Thus, my recommendation, which is documented somewhere deep in the OTP
docs, is to use funs for shortlived local tasks, and {M,F} whenever
the function is kept for a longer time (e.g. as part of server's
state).

Using {M,F} guarantees that the function can be upgraded without
killing all users of the fun.

> 1), it is apparent that `m' is the target of a call (so e.g. tools like
> `xref' can know about it, and you can easily grep for `m:' in your source
> code. In general, avoid passing around module names as data. (For the same
> reason, it is better to use spawn/1 and spawn/2 than the old spawn/3 and
> spawn/4, if possible. Avoid `apply/3'.)

No!  Using spawn/1 or spawn/2 is even worse if you want to support
code upgrade.  This means that the process will have a reference to
the fun on it's stack, which it never will get rid of.  Thus, loading
two more versions of the module kills the process.

I don't understand why these functions were added in the first place.
I don't think they add anything.

> 2) The `fun ... end' value is a _real_ functional value, and has a
> well-defined arity.
> 
> 3) It is more efficient: a static remote-call `m:f(...)' is a relatively
> fast jump in modern (post-JAM) Erlang implementations, and applications of
> fun-expressions are also quite efficient nowadays, while the {M, F} call
> is basically executed by calling `erlang:apply(M, F, ArgList)' which is
> much slower.

I agree.


Use funs with care.


/martin



More information about the erlang-questions mailing list