Doubt about funs

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

Doubt about funs

Robert Virding-4
Lon Willett <Lon.Willett> writes:
>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.

This was considered but there did not seem to be any point seeing it can
easily be had with "fun (A, ...) -> m:f(A, ...) end".  This, by the way,
will handle module updates of module m as it is just a normal call.

Some other significant benefits with a fun which cannot be handles by
{M,F} are:

1. The fun "function", the one automatically created, doesn't have to be
exported and allows you to keep tighter control of your interface.

2. A fun is a closure over the variable bindings when it was created so
it "imports" free variables.  This is a big one.  For example:

incrementer(X) -> fun (Y) -> Y+X end.

and calling incrementer(15) returns a function which increments a vlue
by 15.

2. Using spawn/1/2 and funs allow you create processes without
exporting "internal" functions.  Plus the closure (but be careful to
keep track of when things are done!).

Ulf Wiger <etxuwig> writes:

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

There is a little misconception about the implementation here.  Yes, a
normal Erlang function is created for a fun with a funny name which
actually gives some indication of where the fun is defined, at least in
which function.  The fun "object" contains a (indirect) reference to
this *name*.  It also contains the module name and a unique module id.

This means that:

1. The module name and id mean that you can call funs which are defined
in the old version of code, not just in the new version.  A fun is
therefore usable over one module update.

2. There are no problems when updating a module about moving things,
add/removing funs etc.  A fun contains an identifier to which version
of a module it was defined in, it won't just test the new version.

3. Seeing funs reference a module and do not contain the code they run
they don't "live forever" like other data, or rather are "usable
forever".  When the module has been pruged out you can no longer call
the fun.  But they are safe during their lifetime.

Getting back to the {M,F} versus fun question.  They actually *mean* two
different things even though the syntax for using them is the same.
As long as you are aware of this then there are no real problems.  I
personally never use {M,F} and only use funs for temporary things, like
for higher-order functions.  I have had no problems with module
versions, but then again my funs are short lived.

        Robert






Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Chris Pressey
In reply to this post by Erik.Johansson
"Erik.Johansson" wrote:
> 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 ;)

Can a lowly newbie like myself get in on this action? :-)

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

Earlier, Martin Bjorklund wrote:
> 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.

To me, "short-lived" has little to do with it...

As I understand it - fun objects were introduced into Erlang so that
functions passed to and returned from other functions could be anonymous
(and so they could "lift" closure variables, which obviously cannot be
done inside named functions).

So when I go to write a function I generally ask myself - is it a
rendez-vous point - does it deserve a name?  If it's going to be
referred to elsewhere, it will need one.  If not, it's local and should
probably be a fun.

Here's the interesting question, though.  How would one go about making
a tail-recursive (anonymous) fun anyway?  It can't call itself, because
it doesn't have a name  :-)

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Martin Bjorklund-2
Chris Pressey <cpressey> wrote:

> Here's the interesting question, though.  How would one go about making
> a tail-recursive (anonymous) fun anyway?  It can't call itself, because
> it doesn't have a name  :-)

You'd have to do something along these lines:

g() ->
  F = fun(G) ->
         io:format("looping forever\n"),
         G(G)
      end,
  F(F).


/martin


Reply | Threaded
Open this post in threaded view
|

Doubt about funs

Richard Carlsson-4
In reply to this post by Lon Willett

On 21 Feb 2001, Lon Willett wrote:

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

It has been vaguely discussed (in the work on creating a Standard Erlang
specification), but then restricted to built-in functions only (since
these are known not to change), like `fun erlang:length/1'. It never
caught on, though, and I don't think it was a very useful idea.

After some more pondering about the problem of funs and code change, I
think that the main issue is the use of the `F(...)' syntax. A simple
rule should suffice here: if the callback value could be rather old, so
that its target module might have been replaced once or more since the
value was passed, then *do not use `F(...)' for the callback*.

If we write code for a server or similar long-lived process, allowing
clients to send us callbacks (in some form), then there are two possible
situations:

In the first case, we apply the callback as soon as we handle the
message in which it was passed. In this case, we can allow the client to
pass a fun which we apply using `F(...)', because we can assume that
there hae been no code change between its creation and its application.
(It is of course possible that the fun is already "stale" when sent to
us, but this is not really different from being sent a fun which is
broken in some other way.)

In the second case, we ourselves are storing the callback for later use.
We thus know that when we eventually apply it, the callback module could
have been replaced any number of times since we were passed the value.
In this case, we should probably not use `F(...)' (even when it would be
tempting). We should instead decide on a format for the callbacks, such
as `{hook, Module, FunctionName, Arity}', match out the components, and
call `Module:FunctionName(...)'. In this way, we are *sure* that we do
not crash the program by replacing client code (as long as the code
remains functionally compatible), because we avoid applying any given
fun-values that could have become stale *while we were storing them*.

Thus, I say: never use F = {M,N} when you are going to call F with
F(...) - and vice versa, if you *want* a dynamic call, do it by matching
out and calling M:F(...). For a function that takes a callback as
argument, either document that it should be a fun, *or* a tuple
representing a function name in some way, but do not allow both.

The details of how a dynamic call-back hook should look (e.g., should it
include arity and/or "user data"?) are probably best left for the
programmer to decide for his particular application. (Maybe for OTP to
standardize.) There might even be reason to include a syntax for it in
the language, but I don't have any really good suggestions right now.

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

Core Erlang minor update

Richard Carlsson-4

A small update of the Core Erlang specification has been made. See

        http://www.csd.uu.se/projects/hipe/cerl/

for details.

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

Core Erlang minor update

Robert Virding-4
Richard Carlsson <richardc> writes:
>
>A small update of the Core Erlang specification has been made. See
>
> http://www.csd.uu.se/projects/hipe/cerl/
>
>for details.

I must make one small point here.

The current BEAM compiler already uses Core internally.  It is,
however, not quite the same Core as richard has documented although
they are (slowly) converging.  One major difference is the that the
internal representations are different even though the textual forms
are very alike.

If you are interested in looking at it check out the core_XXX
modules.  To see the how Erlang is converted to Core try the following
compiler flags:

dcore - direct Core representation of the Erlang code
dcopt - Core code after optimisation

You can directly write Core modules but it is not really supported.
There is no benefit in doing it, although in some respects the Core
language has some nice features, and some features which make it a
pain to use directly.

        Robert
--
Robert Virding                          Tel: +46 (0)8 545 55 017
Alteon Web Systems                      Email: rv
S:t Eriksgatan 44                       WWW: http://www.bluetail.com/~rv
SE-112 34 Stockholm, SWEDEN
"Folk s?ger att jag inte bryr mig om n?gonting, men det skiter jag i".


Reply | Threaded
Open this post in threaded view
|

Core Erlang minor update

Robert Virding-4
Robert Virding <rv> writes:
>If you are interested in looking at it check out the core_XXX
>modules.  To see the how Erlang is converted to Core try the following
>compiler flags:
>
>dcore - direct Core representation of the Erlang code
>dcopt - Core code after optimisation

I forgot to mention that the first one produces a .core file
and the second one a .coreopt file.  These contain the
converted/optimised code.

        Robert


12