[erlang-questions] Futures/promises and ability to "call" abstract modules
Dmitry Belyaev
be.dmitry@REDACTED
Tue Nov 20 04:48:23 CET 2012
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:2:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> F = (fun() -> FM = fun(M, V) -> receive {value, Value} -> M(M, Value); {get, P} -> P ! V, M(M, V) end end, P = spawn(fun() -> FM(FM, undefined) end), fun() -> P ! {get, self()}, receive V -> V end end end)().
#Fun<erl_eval.20.82930912>
2> F().
undefined
3> element(2,lists:keyfind('P', 1, lists:flatten(element(2,erlang:fun_info(F, env))))) ! {value, 10}.
{value,10}
4> F().
10
5>
--
Dmitry Belyaev
On 19.11.2012, at 18:05, Gleb Peregud wrote:
> Then I wouldn't be able to set future's value after it being defined.
> Like in this example:
>
> 7> F = future:new().
> {future,<0.47.0>,#Ref<0.0.0.27235>,undefined}
> 8> spawn(fun() -> timer:sleep(10000), F:set(42) end).
> <0.49.0>
> 9> F:get().
> 42
>
> Without this ability such futures are useless with request-reply pattern:
> 1) Client sends request
> 2) Server creates a future and sends it back to client
> 3) Client does it's work with the value of the future (without
> bothering the fact that value may become available in uncertain
> future)
> 4) Server finishes computations and sets future's value
>
>
> On Mon, Nov 19, 2012 at 3:01 PM, Robert Virding
> <robert.virding@REDACTED> wrote:
>> Wouldn't it be easier if future:new just returned a fun? Then you could do F() without any changes?
>>
>> Robert
>>
>> ----- Original Message -----
>>> From: "Gleb Peregud" <gleber.p@REDACTED>
>>> To: "Vlad Dumitrescu" <vladdu55@REDACTED>
>>> Cc: "Erlang" <erlang-questions@REDACTED>
>>> Sent: Monday, 19 November, 2012 2:18:11 PM
>>> Subject: Re: [erlang-questions] Futures/promises and ability to "call" abstract modules
>>>
>>> With the these changes [1] the following code works as intended:
>>>
>>> 7> F = future:new(fun() -> timer:sleep(5000), 42 end).
>>> {future,<0.44.0>,#Ref<0.0.0.71>,undefined}
>>> 8> F().
>>> 42
>>>
>>> Aside from a problem where it improperly reports arity in case of
>>> undefined function:
>>>
>>> 9> F(1,2,3).
>>> ** exception error: undefined function future:call/3
>>>
>>> 1: https://github.com/gleber/otp/compare/call-abstract-module
>>>
>>> On Mon, Nov 19, 2012 at 11:48 AM, Gleb Peregud <gleber.p@REDACTED>
>>> wrote:
>>>> Sverker Eriksson wrote the following in [1]:
>>>>
>>>>> But even if the resource terms look alike, they are unique and
>>>>> there is
>>>>> no bug leaking NIF resources (that I know of). A resource is
>>>>> released
>>>>> (and destructor called) when the last reference is garbage
>>>>> collected.
>>>>> The shell can fool you however, as it keeps a command history that
>>>>> can
>>>>> retain terms even though you think the variables are forgotten.
>>>>> Test NIF
>>>>> resource cleanup by running a test module and call
>>>>> erlang:garbage_collect to force destructors to be called.
>>>>
>>>> This seems to mean that they are "shared" and garbage collected
>>>> just once.
>>>>
>>>> 1:
>>>> http://erlang.org/pipermail/erlang-questions/2011-January/055524.html
>>>>
>>>> On Mon, Nov 19, 2012 at 11:46 AM, Vlad Dumitrescu
>>>> <vladdu55@REDACTED> wrote:
>>>>> I have no idea, that's why I asked :-)
>>>>> /Vlad
>>>>>
>>>>>
>>>>> On Mon, Nov 19, 2012 at 11:44 AM, Gleb Peregud
>>>>> <gleber.p@REDACTED> wrote:
>>>>>>
>>>>>> I assumed that NIF-generated resources are shared between
>>>>>> processes (the
>>>>>> same way as large binaries are), and I haven't done any tests on
>>>>>> this. Are
>>>>>> you sure it is garbate collected multiple times (once per
>>>>>> referencing
>>>>>> process)?
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Nov 19, 2012 at 11:41 AM, Vlad Dumitrescu
>>>>>> <vladdu55@REDACTED>
>>>>>> wrote:
>>>>>>>
>>>>>>> Hi Gleb,
>>>>>>>
>>>>>>> just a quick observation about garbage collecting futures: would
>>>>>>> the
>>>>>>> NIF-generated resource keep track of usage across processes? I
>>>>>>> fI send a
>>>>>>> future as a message, it may be referenced by multiple processes
>>>>>>> which have
>>>>>>> their own heap and garbage collection...
>>>>>>>
>>>>>>> regards,
>>>>>>> Vlad
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Nov 19, 2012 at 11:32 AM, Gleb Peregud
>>>>>>> <gleber.p@REDACTED>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> Hello
>>>>>>>>
>>>>>>>> Last evening I was trying to implement futures/promise
>>>>>>>> mechanism in
>>>>>>>> Erlang (mostly for fun, since I am still unsure if it is
>>>>>>>> useful). I got
>>>>>>>> inspired with the presentation [1], which mentioned using
>>>>>>>> futures as a
>>>>>>>> foundation of building services, where things like timeouts,
>>>>>>>> tracing,
>>>>>>>> authentication, etc. is built by composing futures (see slide
>>>>>>>> 41).
>>>>>>>>
>>>>>>>> Do you think that such composition of futures could be useful
>>>>>>>> as a tool
>>>>>>>> to improve code reuse of communication patterns in Erlang (as
>>>>>>>> described in
>>>>>>>> the presentation)?
>>>>>>>>
>>>>>>>> I've implemented futures using processes and message passing
>>>>>>>> and
>>>>>>>> stumbled upon two issues:
>>>>>>>> 1) garbage collection of futures
>>>>>>>> 2) slightly too much code when using them
>>>>>>>>
>>>>>>>> Example of the first problem is here:
>>>>>>>>
>>>>>>>> 1> F = future:new(fun() -> timer:sleep(10000), 10 end).
>>>>>>>> {future,<0.36.0>,#Ref<0.0.0.1736>,undefined}
>>>>>>>> 2> F:get(). %% it hangs for 10 seconds
>>>>>>>> 10
>>>>>>>>
>>>>>>>> Since future F is represented as a process <0.36.0> it will
>>>>>>>> stay running
>>>>>>>> forever till it's timed out (which is not a good solution,
>>>>>>>> since someone may
>>>>>>>> still have a reference to this future) or F:done() manually
>>>>>>>> called.
>>>>>>>>
>>>>>>>> My idea is to insert into 'future' tuple a NIF-generated
>>>>>>>> resource, which
>>>>>>>> will have a destructor attached (called upon garbage collection
>>>>>>>> of the
>>>>>>>> resource) which will call F:done(). Will it work?
>>>>>>>>
>>>>>>>> The second issue is illustrated here:
>>>>>>>>
>>>>>>>> 7> F = future:new().
>>>>>>>> {future,<0.47.0>,#Ref<0.0.0.27235>,undefined}
>>>>>>>> 8> spawn(fun() -> timer:sleep(10000), F:set(42) end).
>>>>>>>> <0.49.0>
>>>>>>>> 9> F:get().
>>>>>>>> 42
>>>>>>>>
>>>>>>>> In ideal world it should be enough to just write "F" (without
>>>>>>>> :get()) to
>>>>>>>> fetch future's value, but it seems too far fetched for Erlang.
>>>>>>>> Slightly
>>>>>>>> better solution would be to allow calling future with "F()".
>>>>>>>>
>>>>>>>> This can be done by extending concept of "abstract modules"
>>>>>>>> with
>>>>>>>> "default call". Currently abstract modules allow the following:
>>>>>>>>
>>>>>>>> {future, Pid, Ref, undefined}:get() which is translated to
>>>>>>>> future:get({future, Pid, Ref, undefined})
>>>>>>>>
>>>>>>>> With a simple change in beam_emu.c in call_fun function (which
>>>>>>>> would
>>>>>>>> replace obsolete fun tuples) we can allow for the following:
>>>>>>>>
>>>>>>>> {future, Pid, Ref, undefined}() which COULD be translated to
>>>>>>>> future:call({future, Pid, Ref, undefined})
>>>>>>>>
>>>>>>>> hence allowing to use just "F()" to read a value of the future.
>>>>>>>> This
>>>>>>>> will also extend "metaprogramming" capabilities of Erlang for
>>>>>>>> some other
>>>>>>>> quirky use, which may or may not be a Good Thing(tm).
>>>>>>>>
>>>>>>>> Thoughts?
>>>>>>>>
>>>>>>>> Cheers,
>>>>>>>> Gleb Peregud
>>>>>>>>
>>>>>>>> 1: http://monkey.org/~marius/talks/twittersystems/
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> 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
More information about the erlang-questions
mailing list