Doubt about funs

Martin Bjorklund mbj@REDACTED
Wed Feb 21 09:52:58 CET 2001


"Erik Johansson" <happi@REDACTED> wrote:

> The point is really that you should not hold on to funs over code
> change.

That's what I tried to say.  I objected to Richard's statement that
a fun() is always prefered over {M,F} tuples.

> But there is no reason to do so either. If the code defining the fun is
> changed then the code that applies the fun should get a new fun.

How do you propose this should be done in practise?  You'd have to
make sure that all processes (ets tables, files, ...) which holds a
function gets notified when the new code is loaded.  This is simply
not feasible.

> You could run in to similar problems with F = {m,f} if you change the module
> m so that f does not exist, or the arity of f changes, or the implementation
> of f changes, then applying F is not a good idea.

Of course, but in that case the programmer made the choice to change
or remove the function.  With a fun, this happens whether the
programmer wants it or not.

> It might even be an argument for using a fun instead of a tuple in the
> current implementation:
>  * If a process is holding on to a fun and the implementation of the fun is
> changed twice then that process is killed, and the supervisor can start up
> the process again in a correct way.

Surely you can't be serious.  Code change by crashing might be an
interesting area of research ;-)

>  * If a process is holding on to a mod-fun-tuple then the run-time system
> can't detect this and the process will keep on living and applying {m, f}
> even if the intention of the new code would be to apply {m, g}.

Again, this is under the control of the prgrammer with {M,F}.

> > >  (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.
> 
> No! That is not true.
> (Unless the fun is not tail-recursive, but that is not specific for funs.
>  If you want to support code upgrade you will use tail-recursive functions
> as much as possible anyway.)
> 
> spawn( fun () -> m:f(X1, ..., Xn) end)
                  ^^
you probably mean  fun() -> f(...), otherwise you'd have to export f
anyway!

>  has the same effect as
> spawn(m, f, [X1, ..., Xn])

What you describe is not how it works today:

====================================
-module(t).
-export([t/0]).


t() ->
    spawn(fun() -> loop() end).

loop() ->
    receive
	ok ->
	    loop()
    end.
====================================
1> c(t).
{ok,t}
2> P = t:t().
<0.32.0>
3> process_info(P, current_function).
{current_function,{t,loop,0}}
4> l(t).
{module,t}
5> process_info(P, current_function).
{current_function,{t,loop,0}}
6> l(t).
{module,t}
7> process_info(P, current_function).
undefined



> > Use funs with care.
> 
> Yes that is certainly true.
> But as Richard wrote there are several advantages of using funs over a
> tuple, and I can see no real advantage of using the tuple approach.
> Correct behaviour for code change can just as easily be achieved with funs
> as with "apply tuple"; you just need to think about it in a new way.

I still disagree.  A scheme in which code change is achieved by
uncontrolled crashes is not really what we're looking for.  If you can
find a way to change code of funs in a real, distributed system,
please let us know!!

Just to make my point clear, I do like funs, and I use them all the
time, but only for short-lived tasks like in a local lists:foreach
etc.  In code that e.g. registers callbacks to be invoked at a later
time, I use the tuple syntax.


/martin




More information about the erlang-questions mailing list