Doubt about funs

classic Classic list List threaded Threaded
27 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Doubt about funs

chandru
The correct function is selected by the number of arguments to the Fun.

cheers,
Chandru

> -----Original Message-----
> From: Paulo Ferreira [mailto:paf]
> Sent: 20 February 2001 16:26
> To: erlang-questions
> Subject: Doubt about funs
>
>
>   Well, here is my doubt:
>
>  Taken fom the Erlang Extensions doc:
>
> "We can also refer a function defined in a different module with
> the following syntax:
>
> F = {Module,FunctionName}  "
>
>
> In this case, how does Erlang gets the correct function, if
> in the module are several functions, with the same name
> but with different arity ?
>
>
> I know it gets the correct function, at least in the same module,
> because I tested it.
>
>
> Thanks
>
>  Paulo Ferreira
>
>
> ------------------------------------------------
> Paulo Ferreira paf
>
>



NOTICE AND DISCLAIMER:
This email (including attachments) is confidential.  If you have received
this email in error please notify the sender immediately and delete this
email from your system without copying or disseminating it or placing any
reliance upon its contents.  We cannot accept liability for any breaches of
confidence arising through use of email.  Any opinions expressed in this
email (including attachments) are those of the author and do not necessarily
reflect our opinions.  We will not accept responsibility for any commitments
made by our employees outside the scope of our business.  We do not warrant
the accuracy or completeness of such information.



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Richard Carlsson-4

> "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

Why?

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'.)

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.


        /Richard Carlsson


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/




Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Paulo Ferreira

>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
>
>Why?
>
>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'.)
>
>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.
>
>
> /Richard Carlsson
>
>
>Richard Carlsson (richardc)   (This space intentionally left blank.)
>E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/

Thanks to all that replied, but this last answer should be on the FAQ,
or at least on the documentation.

So, here is another advantage of erlang: One doubt and in two hours time
I have five correct answers !!!

Greetings from Porto,Portugal

Paulo Ferreira

------------------------------------------------
Paulo Ferreira paf




Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
In reply to this post by Richard Carlsson-4
Richard Carlsson <richardc> 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


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Happi

"Martin Bjorklund" wrote
[...]

> > 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.

You have a point there, but your statement is not completely true. What you
describe will happen in the current implementation if the function defining
F is changed (or any funs are added or removed before the fun defining F).
But if you do the code change carefully you can actually change code in the
module defining F and F will upgrade to new code.

The point is really that you should not hold on to funs over code change.
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.
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.

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.
 * 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}.

(The semantics of funs and code-change is an interesting topic and any input
is welcome. ;)

[...]
> >  (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)
 has the same effect as
spawn(m, f, [X1, ..., Xn])

With the added benefit that you in the module m can write
spawn( fun () -> f(X1, ..., Xn) end)
without exporting f/n.

[...]
> 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 hope you can see my point through my muddy presentation; it has been a
long day.


/Erik






Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Jim Larson
In reply to this post by Richard Carlsson-4
In message <Pine.GSO.4.21.0102201817150.8698-100000> you write:

>
>> "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
>
>Why?
>
>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'.)

Do you also advise against the use of callback interfaces? If so,
how to you implement the desired dynamic dispatch? Pass funs to an
initialization function?

Jim


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
In reply to this post by Happi
"Erik Johansson" <happi> 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



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Richard Carlsson-4
In reply to this post by Jim Larson

On Tue, 20 Feb 2001, Jim Larson wrote:

> >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'.)
>
> Do you also advise against the use of callback interfaces? If so,
> how to you implement the desired dynamic dispatch? Pass funs to an
> initialization function?

No, sometimes a dynamic lookup is definitely what you want, but this can
be more neatly expressed with the normal remote-call syntax:

        f(Mod) ->
            receive
                Pattern1 -> Mod:f(...);
                Pattern2 -> Mod:g(...);
                Pattern3 -> Mod:h(...);
                ...
            end

Calling `apply/3' is not necessary unless you are writing something like
an interpreter, where even the number of arguments in each call could vary.

(Using Mod:f(...), where Mod is not a constant atom, makes it impossible
for xref to know about the call, but at least you can grep for ":f(".)

My main point was just against the use of pseudo-functional values
`{M, F}' which do not have the same semantics as real functional values
(with respect to arity and dynamic lookup), not against dynamic lookup in
general.

        /Richard Carlsson


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Siri Hansen-2
In reply to this post by Richard Carlsson-4
>  Taken fom the Erlang Extensions doc:
>
> "We can also refer a function defined in a different module with
> the following syntax:
>
> F = {Module,FunctionName}  "
>

The documentation also says that you can use the test function/1 in a
guard to check if a term is a fun. This test fails for the
{Module,FunctionName} expression.

Why?

/siri


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Ulf Wiger-4
In reply to this post by Martin Bjorklund-2

I basically agree with Martin, but...


On Wed, 21 Feb 2001, Martin Bjorklund wrote:

>"Erik Johansson" <happi> wrote:

>>  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


Erm, what did you intent to demonstrate here?
P crashes, but that doesn't really have anything to do with the
fun. It's because t:loop() executes in the old module.
If you change loop() like this:

loop() ->
    receive
        ok ->
            t:loop()
    after 1000 ->
            t:loop()
    end.

then P won't crash.

Indeed, if you make a stack trace on P, you will see that there is
no reference to the fun on the stack (if I read the stack trace
correctly):

39> erlang:process_display(P, backtrace).
program counter = 0x19a8f4 (t:loop/0 + 4)
cp = 0xed830 (<terminate process normally>)
arity = 0
true


The main gripe about long-lived funs is exactly that they sometimes
surprise you during code change. Upgrades are hard enough as it is.
This could perhaps be remedied -- it's certainly improved a lot
already, compared to you only needed to recompile to break all
references to a fun.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Ulf Wiger-4
In reply to this post by Siri Hansen-2
On Wed, 21 Feb 2001, Siri Hansen wrote:

>>  Taken fom the Erlang Extensions doc:
>>
>> "We can also refer a function defined in a different module with
>> the following syntax:
>>
>> F = {Module,FunctionName}  "
>>
>
>The documentation also says that you can use the test function/1 in a
>guard to check if a term is a fun. This test fails for the
>{Module,FunctionName} expression.
>
>Why?

Because Erlang has no way of telling if {M, F} is any ordinary tuple
of two atoms, or a reference to a specific function.

Erlang can, on the other hand tell the difference between a fun() and
a tuple. In older implementations of funs, it couldn't do that,
and you could create a 5-tuple that could pass for a fun(), until you
tried calling it.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
In reply to this post by Ulf Wiger-4
Ulf Wiger <etxuwig> wrote:

> P crashes, but that doesn't really have anything to do with the
> fun. It's because t:loop() executes in the old module.

Yes, of course, you're right.

Ok, so I agree you can use a fun to spawn a new function, if you don't
want to export that function.  I guess it's a matter of taste (and
tradition).

But the main point about code change is still valid though.


/martin


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Ulf Wiger-4
In reply to this post by Martin Bjorklund-2
On Wed, 21 Feb 2001, Martin Bjorklund wrote:

>"Erik Johansson" <happi> wrote:
>
>> 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.

Since funs are actually made into real functions by the compiler, they
seem to have roughly the same properties as ordinary functions during
code change. I've run some tests, and it does seem to be the case that
as long as the fun is tail recursive (doesn't wait for a return
value), then upgrading doesn't break the fun as long as the arity
stays the same. This is the same as for ordinary functions.

It then becomes an issue of interface management.

In general, changing interfaces in an incompatible manner during
system upgrade is asking for trouble -- especially if it's a callback
function which is relatively frequently used. It doesn't really matter
if it's a fun or a variable like Module or {Module, Function};
you still have to suspend all processes referencing the function and
upgrade all of them at the same time.

I will admit that my fear of funs in this context is based on
previous experiences. Most of the past problems appear to have been
fixed.

Still, I would like to see a uniform method of specifying what _is_
actually part of an interface, in a way that you can easily spot what
has changed. It would be nice if this method allowed for automated
analysis.

We (AXD 301) try to collect interface functions in a separate
interface module. This doesn't cover exported records and funs,
however. Regarding records, the .hrl file must be published in a
special library subdirectory, and users of the .hrl are not allowed to
include it directly from the application's inc/ directory. Thus, we
can see what compile-time dependencies are exported from an
application. This is non-OTP-standard, though (there doesn't seem to
be an OTP standard that addresses the issue.)

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
Ulf Wiger <etxuwig> wrote:

> Since funs are actually made into real functions by the compiler, they
> seem to have roughly the same properties as ordinary functions during
> code change. I've run some tests, and it does seem to be the case that
> as long as the fun is tail recursive (doesn't wait for a return
> value), then upgrading doesn't break the fun as long as the arity
> stays the same. This is the same as for ordinary functions.

erik> What you describe will happen in the current implementation if
erik> the function defining F is changed (or any funs are added or
erik> removed before the fun defining F).

So, it's still a problem.  If this problem was solved, so that it
worked as you described above, I'd be the first to start using funs
for everything!


/martin



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Ulf Wiger-4
On Wed, 21 Feb 2001, Martin Bjorklund wrote:

>Ulf Wiger <etxuwig> wrote:
>
>> Since funs are actually made into real functions by the compiler, they
>> seem to have roughly the same properties as ordinary functions during
>> code change. I've run some tests, and it does seem to be the case that
>> as long as the fun is tail recursive (doesn't wait for a return
>> value), then upgrading doesn't break the fun as long as the arity
>> stays the same. This is the same as for ordinary functions.
>
>erik> What you describe will happen in the current implementation if
>erik> the function defining F is changed (or any funs are added or
>erik> removed before the fun defining F).

Yes, you're right. Adding a fun before a fun referenced by some
process P, will cause P to crash when the old module is purged.

Oops.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Erik.Johansson
In reply to this post by Martin Bjorklund-2
 
Paulo Ferreira  wrote:
> So, here is another advantage of erlang: One doubt and in two hours time
> I have five correct answers !!!
And then the obligatory debate starts ;)

Ulf Wiger wrote: (cited out of context)
> I will admit that my fear of funs in this context is based on
> previous experiences. Most of the past problems appear to have been
> fixed.

>It then becomes an issue of interface management.

Yes, this is my point; you can use a fun just as well as {M, F} but you would have to design things a bit differently from the beginning.
 
My real concern is what the semantics for funs during code change should be. In the current system processes holding on to funs that changes twice get killed. Some say this is good because then you can be sure that old code is phased out.  I would like to try a different behavior where existing funs holds on to the code as long as needed in stead. This could lead to an ever increasing amount of code if one is not careful, but isn't that better than having processes crash if you are not careful?
 
Martin Bj?rklund wrote:
> erik> What you describe will happen in the current implementation if
> erik> the function defining F is changed (or any funs are added or
> erik> removed before the fun defining F).
>
> So, it's still a problem.  If this problem was solved, so that it
> worked as you described above, I'd be the first to start using funs
> for everything!
 
Yes it is still a problem, but if you know about it and are careful with how you use funs, you can use them for everything.
And please lobby for a nice semantic for funs and code change.
 To summarize my view:
 1. For short lived tasks: always use a fun.
 2. For spawing use a tail-recursive fun.
 3. For long-lived (call-backs) either make a careful design or stick to {M., F} if you feel that it is easier.

/Erik

                                   
 



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
"Erik.Johansson" <Erik.Johansson> wrote:

> My real concern is what the semantics for funs during code change
> should be. In the current system processes holding on to funs that
> changes twice get killed. Some say this is good because then you can
> be sure that old code is phased out.

I think that is good.

> I would like to try a different behavior where existing funs holds
> on to the code as long as needed in stead. This could lead to an
> ever increasing amount of code if one is not careful, but isn't that
> better than having processes crash if you are not careful?

One problem with this is that you would have to come up with a way to
explicitly tell all users of the fun that it's time to refresh.  This
is something you need, since the code might be updated because of bug
fixes or new features, and you definately want to change all
occurences of the old fun in the system.  External calls takes care of
that today.

> And please lobby for a nice semantic for funs and code change.

I agree, it's an important area.

>  To summarize my view:
>  1. For short lived tasks: always use a fun.
>  2. For spawing use a tail-recursive fun.
>  3. For long-lived (call-backs) either make a careful design or
>     stick to {M., F} if you feel that it is easier.

I agree with this as well.  The only concern I have with "careful"
design is that it might be difficult to do in real code.  For example,
how can I make sure that the function that defined the fun is not
changed in a future version?  Well, I could define a function with the
only purpose of returning the fun.  Then, how would I make sure that
no funs are added/removed before this one?  I could declare all funs
in a section at the end of the module, and always add funs after the
ones defined, and never remove stale funs.  I'm not sure I like that
approach though.


/martin


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Richard Carlsson-4
In reply to this post by Martin Bjorklund-2

On Wed, 21 Feb 2001, Martin Bjorklund wrote:

> Ulf Wiger <etxuwig> wrote:
>
> > Since funs are actually made into real functions by the compiler, they
> > seem to have roughly the same properties as ordinary functions during
> > code change. I've run some tests, and it does seem to be the case that
> > as long as the fun is tail recursive (doesn't wait for a return
> > value), then upgrading doesn't break the fun as long as the arity
> > stays the same. This is the same as for ordinary functions.
>
> erik> What you describe will happen in the current implementation if
> erik> the function defining F is changed (or any funs are added or
> erik> removed before the fun defining F).

Never depend on funs "migrating" from old code to new, even if you did not
add or remove funs from the code (i.e., even if the internal fun-indexing
inside the module stays the same over the code change). The code executed
by a fun should be exactly that in the version of the module used to
create the fun-value. Coming Erlang implementations will assure this by
using a module-checksum to identify the correct code for a fun, or crash
the call if that version has been purged. (In the current implementation a
fun could only survive at most one code change anyway, so it was not
really much of a help. The new scheme is more consistent.)

        /Richard

Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/



Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Erik.Johansson
In reply to this post by Martin Bjorklund-2
 "Martin Bjorklund" <mbj> wrote:
> One problem with this is that you would have to come up with a way to
> explicitly tell all users of the fun that it's time to refresh.  This
> is something you need, since the code might be updated because of bug
> fixes or new features, and you definately want to change all
> occurences of the old fun in the system.  External calls takes care of
> that today.
Well external calls take care of that to a certain degree today, you might still need to explicitly handle changes to interfaces and to data representation.

...
> I agree with this as well.  The only concern I have with "careful"
> design is that it might be difficult to do in real code.  For example,
> how can I make sure that the function that defined the fun is not
> changed in a future version?

What I meant with "careful design" was not to try to write funs that don't change but to design servers so that they explicitly can upgrade to a new fun when the code changes. You say that this is infeasible or difficult in real code but if you are aware of the problem from the outset I don't think it is harder than, for example, the problem of handling changes in the representation of data after code change. (I'm not saying that this is an easy problem. ;) Using a {M., F} instead of a fun don't solve the real problems with code change it just hides some of the deeper problems behind the simplicity of the remote call.

 /Erik




Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Lon Willett
In reply to this post by Richard Carlsson-4
So has anyone considered implementing a syntax like "fun Mod:Fun/Arity"?

It seems like an obvious thing to do.  And even a naive implementation
which just replaced the expression with "{M,F}" (losing the arity)
would at least provide a nice consistent way to express the intent.  A
good implementation would produce some dynamic function object that
was efficient, contained the arity, and was robust across code change.

/Lon
--
Lon Willett <Lon.Willett>
Security Architect, SSE Ltd.
Fitzwilliam Court, Leeson Close
Dublin 2, Ireland
+353-1-216-2946
+353-87-8053539 (mobile)


12