On Wed, Feb 28, 2018 at 2:33 AM, Carsten Haitzler <[email protected]> wrote:
> On Tue, 27 Feb 2018 18:34:59 -0500 Cedric Bail <[email protected]> said:
>
>> -------- Original Message --------
>>  On February 27, 2018 2:52 PM, Carsten Haitzler <[email protected]> wrote:
>>
>> >so I'm implementing a new efl.exe class (and efl.task and some others) and i
>> > WAS going to use a future as the return for run() ... but after just 
>> > writing
>> > about 20 lines of code (get a scheduler, create a promise alloc promise 
>> > data
>> > and all the checking in between) and i then realized... it's ballooning to
>> > an insane amount of code vs event_callback_call which is a 1 line func call
>> > when the event happens.
>> >
>> > let me just copy and paste the relevant lines i had sketched out (was not
>> > final or even compiling yet):
>> >
>> > typedef struct _Efl_Exe_Run_Data
>> > {
>> > Eo *obj;
>> > } Efl_Exe_Run_Data;

not sure you need this

>> > static void
>> > _efl_exe_run_cancel(void *data, const Eina_Promise *dead_ptr EINA_UNUSED)
>> > {
>> > Efl_Exe_Run_Data *d = data;
>> >
>> > efl_task_end(d->obj);
>> >}
>> >
>> > Efl_Exe_Run_Data *d;
>> > Eina_Promise *p;
>> >
>> > d = calloc(1, sizeof(Efl_Exe_Run_Data));
>> > EINA_SAFETY_ON_NULL_RETURN_VAL(d, NULL);
>> > d->obj = obj;
>> >p = eina_promise_new(sched, _efl_exe_run_cancel, d);
>> > EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
>> > d->promise = p;
>> >d->run_future = efl_future_Eina_FutureXXX_then(obj, eina_future_new(p));
>> >return d->run_future;
>>
>> You do not need to keep the future at all in your structure. You are good to
>> go with just :
>>
>> return efl_future_Eina_FutureXXX_then(obj, eina_future_new(p));
>
> then how do i trigger success or failure of the future if i don't have a 
> handle
> on it - well promise/future... whatever. same thing to me. i dislike the whole
> division of promise vs future. to me it's an async task that at some point in
> the future triggers a success or failure then disappears after that.

you just keep the write/send side: Eina_Promise: p... that's where you
send your results.


>> And once we have migrate future<> in .eo to Eina_Future, it will become just 
>> :
>>
>> return eina_future_new(p);
>
> still have to store it in the object to trigger it and pass in results like
> exit codes ... or object handles. and as below. i can't pass an obj handle via
> an eina_value. :( the caller has to remember to pass in the obj as the data
> ptr... not very nice compared to events that always give you the obj the event
> happened on.

you can, there is an EO: EINA_VALUE_TYPE_OBJECT, it's juste declared
down in the stack:

https://git.enlightenment.org/core/efl.git/tree/src/lib/eo/Eo.h#n2049



>> > // XXX: no eina value for eo obj handles... :( call where exe exit handled
>> > Eina_Value *val = eina_value_new(EINA_VALUE_TYPE_UINT64);
>> > eina_promise_resolve(d->run_future, val);
>>
>> This line can be properly written as :
>> eina_promise_resolve(d->promise, eina_value_uint_init(ret));
>
> errr... but i want to pass an object to the promise, not an int...

   eina_value_object_init(obj)


>> > i got to 22 lines and i wasn't even done yet (need to do some more
>> > housekeeping)... vs 1 line for event_callback_call. i'm going with events
>> > until futures/promises are not a crazy amount of code compared to events.
>> > this is it with events:
>> >
>> > efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
>>
>> This is absolutely not doing what the future code is doing. You are not
>> detecting when a user has removed the handler and so call efl_task_end
>> accordingly. You are also not sending a structure with the exit code either
>
> i don't need to send the data in a future - it's stored on the object anyway.
> you pick it up with a get from the object.

well, that's misuse of the promise result... if you're running
something to get data, that's what you should get at the end, not the
object...

if the user needs the object, he can pass that as his future cb data.

the idea is that these things can be chained, including transformations... like:

  bla.run().then(uppercase).then(console.log)

we even offer some converters and a console future for such things.
Actually we should even do more,
like those exposed by http://reactivex.io, handling multiple wait,
debounce, etc.


> oooh... no no no. first - i don;t need know now if the handler has been added
> or removed because callback_call handles that for me.
> and calling end() sent a
> signal to the child process to request it to end... it does not mean it has
> ended yet. so you would never sensibly call end from the exit event cb because
> that's sending end to a process that no longer exists... just the object
> representing it does still to store the results.
>
> so maybe you mean "del()" the object if the caller isn't listening for exit
> events... It'd LOVE to do that, but c++ people will hate autodel... which is
> exactly what that would be.

well, that's exactly what the promise does, and to consider "match
behavior", that's what you should do.

usually with regular events we'd just "forget" about it and leave the
task running, doing its process without cancelling... which is bad
most of the time.


>> (and of course you are not describing it in the .eo file). I don't even see
>> how you can compare this two lines ? And we are not even looking at the user
>> of the API here which is what matter even more. How do you make sure that the
>> event is always delivered properly ? How often do you generate the event
>> (Every time someone register a callback) ? There is a lot of open question
>> with this kind of API that you are just disregarding here.
>
> it's called when the parent process knows the child has exited and what the
> exit code is. there is no guarantee this happens during the life of the object
> at all. the process could become hung on a kernel syscall and never exit, 
> ever.
> that's what the exit event is. when this happens. it's guaranteed to be called
> when this event occurs.
>
> my point is the event is 1 line. futures is a massive blob of code to achieve
> the same goal. i find them basically unusable to the point that i'm just
> avoiding them now. if they were "1 liners" too... then great. but they are 
> not.
> (well they will be a line to create and store, a line in a destructor to 
> cancel
> on destruction if still there and another line in the "where the event 
> happens"
> to either call success or failure with the future data... but it needs to be
> far far far simpler than it is.

you just realize that the code is always the same, right? there is no
magic, we're just doing something on behalf of users, in a clear and
standard way.

so yes, you're doing bit more work so users don't have to. Like
keeping references, canceling, etc. Our hope is that core devs (that
usually deal with eina_promise part) will be more careful with
managements and the likes.

users just pass one callback and *always* get called (even with "ECANCELED").

as for "lines of code", for sure we could offer a way to "add a
promise to this object", it would fetch the "loop" from a loop-user,
then fetch the scheduler... then create the promise and return.

the "cancel the promise" part is already done by the efl_future (note:
"EFL", not "EINA"), which binds the future/promise to the object
life... on destruction they are automatically cleared. As Cedric said,
once old efl_future dies and Eolian gets future<x> mapping, this will
be generated for you.



-- 
Gustavo Sverzut Barbieri
--------------------------------------
Mobile: +55 (16) 99354-9890

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to