one-time evaluated functions

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

one-time evaluated functions

Jarosław Preś
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Anthony Molinaro-4
You can use mochiglobal or a similar trick to do what you want.


-Anthony

On Oct 30, 2017, at 8:41 AM, Jarosław Preś <[hidden email]> wrote:

Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Mikael Pettersson-5
In reply to this post by Jarosław Preś
Yes.

1. (Boring) Have a persistent store somewhere, and have the function check if the value is stored there or not.  If not, compute it and store.  An ETS table would work fine, but you need to ensure it's lifetime matches your requirements.  A plain file containing term_to_binary/1 of the value should also work.  Or use a DB.

2. (More fun) Place the function in a module M.  Initial version computes the value and generates a new version of the module where the function now just returns that constant value.  There will probably be some restrictions on what kinds of values you can return this way, i.e. I wouldn't expect a function value with closed over free variables to work, but anything you could include in a pattern match should work.

On Mon, Oct 30, 2017 at 4:41 PM, Jarosław Preś <[hidden email]> wrote:
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Chandru-4
Here is the code for the boring solution. 

case ets:insert_new(EtsTab, {singleton, undefined}) of
    false ->
        ets:lookup_element(EtsTab, singleton, 2);
    true ->
        Val = evaluate_one_time_function(),
         ets:insert(EtsTab, {singleton, Val}),
        Val
    end.

You have to make sure that the ETS table is owned by some long lived process and is of type public if you are going to invoke this function from multiple processes. 

Cheers
Chandru


On 30 Oct 2017, at 17:05, Mikael Pettersson <[hidden email]> wrote:

Yes.

1. (Boring) Have a persistent store somewhere, and have the function check if the value is stored there or not.  If not, compute it and store.  An ETS table would work fine, but you need to ensure it's lifetime matches your requirements.  A plain file containing term_to_binary/1 of the value should also work.  Or use a DB.

2. (More fun) Place the function in a module M.  Initial version computes the value and generates a new version of the module where the function now just returns that constant value.  There will probably be some restrictions on what kinds of values you can return this way, i.e. I wouldn't expect a function value with closed over free variables to work, but anything you could include in a pattern match should work.

On Mon, Oct 30, 2017 at 4:41 PM, Jarosław Preś <[hidden email]> wrote:
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Chandru-4
Actually this won’t work properly if you have a bunch of requests come in concurrently the first time around. Some of them will see undefined as the result. So you’ll need extra code to sleep and retry if the ets lookup returns undefined (unless undefined is a valid value!)

On 30 Oct 2017, at 17:20, Chandrashekhar Mullaparthi <[hidden email]> wrote:

Here is the code for the boring solution. 

case ets:insert_new(EtsTab, {singleton, undefined}) of
    false ->
        ets:lookup_element(EtsTab, singleton, 2);
    true ->
        Val = evaluate_one_time_function(),
         ets:insert(EtsTab, {singleton, Val}),
        Val
    end.

You have to make sure that the ETS table is owned by some long lived process and is of type public if you are going to invoke this function from multiple processes. 

Cheers
Chandru


On 30 Oct 2017, at 17:05, Mikael Pettersson <[hidden email]> wrote:

Yes.

1. (Boring) Have a persistent store somewhere, and have the function check if the value is stored there or not.  If not, compute it and store.  An ETS table would work fine, but you need to ensure it's lifetime matches your requirements.  A plain file containing term_to_binary/1 of the value should also work.  Or use a DB.

2. (More fun) Place the function in a module M.  Initial version computes the value and generates a new version of the module where the function now just returns that constant value.  There will probably be some restrictions on what kinds of values you can return this way, i.e. I wouldn't expect a function value with closed over free variables to work, but anything you could include in a pattern match should work.

On Mon, Oct 30, 2017 at 4:41 PM, Jarosław Preś <[hidden email]> wrote:
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Pierre Fenoll-2
When I don’t really know the best way to store such a value and it doesn’t change I just create a dedicated and locally named gen_server. 
If the state I want to store is “large” I put it in the gen_server’s pdict which may or may not be a good idea. The process dictionary gets dumped when the server crashes. 

Fred Herbert has an interesting article about the pdict: 

On Mon 30 Oct 2017 at 18:29, Chandrashekhar Mullaparthi <[hidden email]> wrote:
Actually this won’t work properly if you have a bunch of requests come in concurrently the first time around. Some of them will see undefined as the result. So you’ll need extra code to sleep and retry if the ets lookup returns undefined (unless undefined is a valid value!)


On 30 Oct 2017, at 17:20, Chandrashekhar Mullaparthi <[hidden email]> wrote:

Here is the code for the boring solution. 

case ets:insert_new(EtsTab, {singleton, undefined}) of
    false ->
        ets:lookup_element(EtsTab, singleton, 2);
    true ->
        Val = evaluate_one_time_function(),
         ets:insert(EtsTab, {singleton, Val}),
        Val
    end.

You have to make sure that the ETS table is owned by some long lived process and is of type public if you are going to invoke this function from multiple processes. 

Cheers
Chandru


On 30 Oct 2017, at 17:05, Mikael Pettersson <[hidden email]> wrote:

Yes.

1. (Boring) Have a persistent store somewhere, and have the function check if the value is stored there or not.  If not, compute it and store.  An ETS table would work fine, but you need to ensure it's lifetime matches your requirements.  A plain file containing term_to_binary/1 of the value should also work.  Or use a DB.

2. (More fun) Place the function in a module M.  Initial version computes the value and generates a new version of the module where the function now just returns that constant value.  There will probably be some restrictions on what kinds of values you can return this way, i.e. I wouldn't expect a function value with closed over free variables to work, but anything you could include in a pattern match should work.

On Mon, Oct 30, 2017 at 4:41 PM, Jarosław Preś <[hidden email]> wrote:
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
--

Cheers,
-- 
Pierre Fenoll


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Kostis Sagonas-2
In reply to this post by Jarosław Preś
On 10/30/2017 04:41 PM, Jarosław Preś wrote:
> Hi,
>
> Is it possible to make an erlang function be evaluated only once at
> first call and then return this value each time?

Many answers have already been given for this question.  I only want to
point out that the above only works for functions that are pure, in the
sense that they are not only side-effect free (e.g. do not print, send
messages, etc.), but also do not have dependencies on the state in any way.

Kostis
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Sverker Eriksson-4
In reply to this post by Chandru-4
And you should do ets:lookup_element *first*
as that is the normal case
and it only requires a read lock.

/Sverker

On 10/30/2017 06:29 PM, Chandrashekhar Mullaparthi wrote:
Actually this won’t work properly if you have a bunch of requests come in concurrently the first time around. Some of them will see undefined as the result. So you’ll need extra code to sleep and retry if the ets lookup returns undefined (unless undefined is a valid value!)

On 30 Oct 2017, at 17:20, Chandrashekhar Mullaparthi <[hidden email]> wrote:

Here is the code for the boring solution. 

case ets:insert_new(EtsTab, {singleton, undefined}) of
    false ->
        ets:lookup_element(EtsTab, singleton, 2);
    true ->
        Val = evaluate_one_time_function(),
         ets:insert(EtsTab, {singleton, Val}),
        Val
    end.

You have to make sure that the ETS table is owned by some long lived process and is of type public if you are going to invoke this function from multiple processes. 

Cheers
Chandru


On 30 Oct 2017, at 17:05, Mikael Pettersson <[hidden email]> wrote:

Yes.

1. (Boring) Have a persistent store somewhere, and have the function check if the value is stored there or not.  If not, compute it and store.  An ETS table would work fine, but you need to ensure it's lifetime matches your requirements.  A plain file containing term_to_binary/1 of the value should also work.  Or use a DB.

2. (More fun) Place the function in a module M.  Initial version computes the value and generates a new version of the module where the function now just returns that constant value.  There will probably be some restrictions on what kinds of values you can return this way, i.e. I wouldn't expect a function value with closed over free variables to work, but anything you could include in a pattern match should work.

On Mon, Oct 30, 2017 at 4:41 PM, Jarosław Preś <[hidden email]> wrote:
Hi,

Is it possible to make an erlang function be evaluated only once at first call and then return this value each time?

BR/Jarek

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: one-time evaluated functions

Richard A. O'Keefe-2
In reply to this post by Pierre Fenoll-2
Some obvious questions:
  - when does this make sense?
    As others have noted, the function must be pure.
    The cost of re-evaluating the function should
    also be significantly higher than the cost of
    checking, in the context of the whole program.

  - how much does it actually save?
    This depends of course on the actual function.
    It also depends on how much the compiler can
    optimise the function, so the way the function
    is written may be significant.

  - is there prior art for this?

    Eiffel has "once" functions.  In fact it has two
    kinds: once per class and once per instance.  In
    Erlang, the equivalent might be that it makes as
    much sense, if not more, to cache f(X) as f().

    It also reminds us that there are at least two
    versions that might make sense for Erlang: once
    per module, and once per process.

    Smalltalk historically made much use of
    "lazy initialisation" where you do
       cachedValue ifNil: [cachedValue := ...].
    I used that a lot in my Smalltalk system, up
    to the point where I implemented threads.  And
    then, mindful of the "double-checked locking is
    broken" issue, changed it all to load-time
    initialisation.  The one exception is encoding
    and decoding tables, which are loaded on demand,
    and protected by a lock.  In this context, the
    cost of locking was negligible.

What do we learn from this?

(1) It would be possible to have
     -once(f/0, module).
     f() -> ...
     implemented by having the loader load the module
     as usual, call f() getting V, and then patch the
     module to f() -> V.

     Others have explained using ETS tables, which has
     higher overhead, but can be done right now.

(2) It is possible to simulate
     -once(f/0, process).
     by having

     f() ->
         case get({?MODULE,f})
           of undefined ->
              V = real_f(),
              put({?MODULE,f}, [V])
            ; [V] ->
              ok
         end,
         V.

     real_f() ->
         whatever f()'s body would have been.

     This could be done using a parse transform.

(3) Concrete details matter.





_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions