[erlang-questions] Execute module code from stored anonymous function

Tony Rogvall tony@REDACTED
Sun Sep 11 13:39:33 CEST 2016


A local fun ”belongs” to the code module where it is defined.
So the problem is that the definition it self is purged out of the system.

This is not the case with fun mod:fun/a, for example fun erlang:integer_to_list/1 is
just referring to an export entry.

You can still use fun’s to refer to the old version of the definition ( in the old module ) as
long as they are not purged. I some time use this fact to create transaction funs that survive
ONE code reload while executing for example rules that are compiled.

The example below let you create a global ets store for procedures.

> etsfun:create().
> etsfun:store_procedure(f, etsfun:procedure_global1()).
> etsfun:call_procesure(f, 1).
”1”

In this case you reload the ’etsfun’ module as many time as you like since,
the global1 function is not defined in the etsfun module.

> etsfun:create().
> etsfun:store_procedure(f, etsfun:procedure_global2()).
> etsfun:call_procedure(f, 1).
”1”

If you just recompile+reload this module without changing anything that will allow you to
reload any number of times as well. But if you change the module a tine bit
by for example adding a blank in a string ( must be in code ) then you can still call the
function since the old version is still there.
But change code one more recompile+reload and the original fun is purged from the system
and the call will crash, as expected.

This last example with a local function that talks a bit, show this a bit more.

> etsfun:create().
> etsfun:store_procedure(f, etsfun:procedure_local()).
> etsfun:call_procedure(f, 1).
fun 1

Now change the body of the procedure_local() to the one with ”hej” and recompile/reload once.

> etsfun:call_procedure(f, 1).
fun 1

Same result, the same fun. But if you change again and recompile/reload this will crash.

and finally

> etsfun:store_procedure(f, etsfun:procedure_local()).
> etsfun:call_procedure(f, 1).
hej  1

and the new definition is stored.




-module(etsfun).
-compile(export_all).

create() ->
    ets:new(etsfun, [named_table, public]).

store_procedure(Key, F) ->
    ets:insert(etsfun, {Key,F}).

call_procedure(Key,Arg) ->
    [{_,F}] = ets:lookup(etsfun, Key),
    F(Arg).

procedure_global1() ->
    fun erlang:integer_to_list/1.

procedure_global2() ->
    fun(X) ->
	    erlang:integer_to_list(X)
    end.

procedure_local() ->
    fun(X) ->
	    my_local_func(X)
    end.

%% my_local_func(X) -> io:format("hej  ~w\n", [X]).
my_local_func(X) -> io:format("fun ~w\n", [X]).





> On 11 sep 2016, at 10:39, Pierre Fenoll <pierrefenoll@REDACTED> wrote:
> 
> > In your case the pointer to function is stored internally and it goes extinct when module is gone.
> 
> Why is this the behavior? I would expect the fun to properly call the latest version of the module's code if not purged,
> throwing an exception otherwise, not "just throw because version changed".
> 
> Why disallow funs to directly reference version-changing code?
> (indirectly because fun () -> apply(M, F, A) end is still possible)
> 
> 
> I am surprised & interested in the reasons behind having
> 
> * fun () -> mod:fname(Arg1, Arg2, ...) end
> * fun () -> erlang:apply(mod, fname, [Arg1, Arg2, ...]) end
> 
> be semantically different!
> 
> 
> 
> Cheers,
> --
> Pierre Fenoll
> 
> 
> On 11 September 2016 at 09:27, Nuku Ameyibor <nayibor@REDACTED> wrote:
> thanks for quick reply .
> will give it a shot .
> 
> 
> On Sun, Sep 11, 2016 at 7:08 AM, Dmytro Lytovchenko <dmytro.lytovchenko@REDACTED> wrote:
> In your case the pointer to function is stored internally and it goes extinct when module is gone.
> If you make it calculate function at runtime by, say, calling apply(mprocess, process_template, [test]), then it should work.
> 
> sön 11 sep. 2016 kl 08:57 skrev Nuku Ameyibor <nayibor@REDACTED>:
> Dear List ,
> 
> i run into an issue where i was storing an anonymous function in mnesia  to be executed later .
> F=fun(test) ->mprocess:process_template(test)end.
> 
> 
> however  as soon as i make some changes to the mprocess module  and upgrade the module i get a ** exception error: bad function error when i retrieve the fun and try to execute which i assume is because of the difference in the module versions .
> Is there a way of making the stored fun execute the code and not have version conflicts .
> 
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
> 
> 
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
> 
> 
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20160911/0a89307d/attachment.bin>


More information about the erlang-questions mailing list