Hi Felipe & Cedric,

Thanks for explaining the lifecycle in detail, ... but I'm still not
convinced :)


On 14 June 2016 at 02:28, Felipe Magno de Almeida <
felipe.m.alme...@gmail.com> wrote:

> Sorry for top-posting. But let me summarize the Promise lifetime:
>
> A Promise when created starts with a ref-count of 1.
> If the promise is not needed anymore, it should be
> unref'ed (if no eina_promise_then is made, either
> directly or by eina_promise_all/eina_promise_race).
>
> The first eina_promise_then _steals_ the first
> reference, the others eina_promise_then
> increments the reference count.
>
> When the promise is fulfilled (by value_set or error_set),
> then each call to a eina_promise_then decrements
> the reference count by 1.
>
> When the reference count reaches 0 _and_ the
> promise is fulfilled the promise is deleted (both
> conditions must be true, if just one is true it
> continues to exist).
>
> So, valid cases:
>
> Eina_Promise* p = ..;
> eina_promise_then(p, ...);
> // promise will be deleted
> // when callback for the then is called
>
> Eina_Promise* p = ...;
> eina_promise_unref(p);
> // Promise will be freed when promise is fulfilled
> // by error_set or value_set
>
> Eina_Promise* p = ...;
> eina_promise_then(p, ...);
> eina_promise_then(p, ...);
> // promise will be deleted
> // when callback for the then is called
>
> Eina_Promise* p = ...;
> eina_promise_all(p, ...);
> eina_promise_then(p, ...);
> // promise will be deleted
> // when callback for the then is called
>
> Eina_Promise* p = ...;
> eina_promise_all(p, ...);
> // promise will be deleted
> // when callback for the then is called
>
>
So my understanding here is that this can work because a promise can not
ever be synchronous.
In other words, eina_promise_then can never trigger the success/error
callback to be called synchronously, otherwise the above reference count
system falls apart.

While this approach is convenient, it means that we can use an object
(promise) we don't hold any reference on (after first _then).
This is weird :)



> Etc..
>
> Regards,
> --
> Felipe Magno de Almeida
>
>
> On Mon, Jun 13, 2016 at 2:17 PM, Cedric BAIL <cedric.b...@free.fr> wrote:
> > Hello,
> >
> > On Sun, Jun 12, 2016 at 10:13 PM, Jean-Philippe André <j...@videolan.org>
> wrote:
> >> On 13 June 2016 at 03:02, Cedric BAIL <cedric.b...@free.fr> wrote:
> >>> On Wed, Jun 8, 2016 at 4:16 AM, Carsten Haitzler <ras...@rasterman.com
> >
> >>> wrote:
> >>> > On Mon, 6 Jun 2016 06:01:13 +0200 Cedric BAIL <cedric.b...@free.fr>
> >>> said:
> >>> > and you can do the same with eo - you can store the result until cb's
> >>> added or
> >>> > until a go/done/whatever api is called. but that on;y matters if you
> >>> want a
> >>> > specific cb for that specific action. in general if you want that hen
> >>> you want
> >>> > a real object to be returned so you can manage it like other objects.
> >>>
> >>> As said before, basically what you want is an Eo object which doesn't
> >>> behave like a normal eo object. Having its own meaning for ref/unref,
> >>> for events and life cycle. At this point, I don't see how it will be
> >>> easier for people and not more confusing ?
> >>
> >> Efl.Part are EO objects that die after a single function call.
> >> So, we already have objects with a different lifecycle.
> >
> > Yes, but you are not supposed to interact with that said object more
> > than with just one function. What happen if someone do an
> > eo_ref/eo_unref on it ?
>

You can eo_ref() before calling a function, this gives you a "strong" ref
that you then need to eo_unref() manually as well.
This means you can do:

func(efl_part(obj, "a"))

and:

part = eo_ref(efl_part(obj, "a"))
func1(part)
func2(part)
func3(part)
eo_unref(part)

Only func1() will unref the part object implicitely. An internal flag
insures that func2 and func3 don't also trigger an unref.

The same model could be used for promises that we want to stuff into more
than one _then, _race or _all.


>> Events are the same: they call a callback function with a user data and
> an
> >> event info (promise value).
> >
> > No. Event in promise will keep their value until all the reference to
> > the promise exist and each time that a callback is triggered that
> > reference count goes down by one. There is also an absolute guaranty
> > that you can not destroy a promise without having all the reference
> > receiving either a succeed or a fail. Also the returned value of an
> > event handler for then or cancel should be ignored as you can not stop
> > notifying anyone in the chain and the state should stay either success
> > or failure once it has been decided.
>

It is actually a good question whether the return bool is a good idea or
not.
If you return false in evas callbacks, you're gonna be in trouble.

The ON_HOLD flag, now called efl_event_processed_get/set() is a better
approach to stop processing events.



> >> For how long is a promise handle valid?
> >> Is it valid up until eina_promise_then? What if you just stuff the
> promise
> >> in a _race or _all?
> >
> > A promise is expecting one couple of cancel/then to be registered.
> > Once it is, that promise can still be cancelled by the user if it has
> > not triggered any of the callback it registered for, any other use
> > will be illegal. If it give it to a _race or _all, he obviously loose
> > his chance to register callbacks, so if he want to register them, he
> > need to increase the ref count.
> >
> >> Can you ignore a promise handle altogether? (I guess it would leak)
> >
> > Will leak inded and make no sense as it is delivering something at the
> > end of the pipe. If you do not want it, well, why did you ask for it ?
> > :-)
>

Because you might actually not have much of a choice, in some APIs like an
async file_set (imaginary for now).



> >> Anyway it seems the only difference here is that a promise starts the
> >> action as soon as possible, while an eo object would have to
> explicitely be
> >> marked as ready (which is very similar to starting the action during
> >> eina_promise_then).
> >
> > No, the main difference is that the life cycle is linked to the
> > callbacks and that their should not be any way to bypass it. eo_del
> > should also be forbidden for example on a promise as only a cancel
> > make sense. Of course we could alias it, and make sure that cancel
> > don't destroy the parent. We can also override all eo event API and
> > make sure they do what we want, but we can't at the moment override
> > eo_ref and eo_unref. The alternative would be to create an Eo_Promise
> > which doesn't inherit from Eo_Base (Or make an Eo_Light that both
> > would inherit from) and would kind of make clear that it is not an Eo
> > object, but a promise object (Given that eo_ref and eo_unref become
> > virtual function).
> >
> > Also at which point do you think user are going to be confused by an
> > Eo object where every single function call on it has its own
> > documentation and doesn't behave like a normal eo object ?
>

That's where we still disagree :)

I still have trouble understanding how fundamentally different those two
objects are.
In fact I see a lot of similarities between a (conceptual) promise and
Efl.Part.


From my understanding, the main difference is that a promise callback WILL
be called, be it the error or success, one of them will be, for each _then,
_race and _all that was setup. Which can be enforced with a commit approach:

// same syntax as eina_promise:
p = promise_function(obj)
eo_promise_then(p, _success, _error, data) // this is a HELPER based on eo
events, implemented in Eo.Promise, steals the ref


// it would be equivalent to:
p = promise_function(obj)
eo_event_callback_add(p, PROMISE_EVENT_FAILURE, _error, data)
eo_event_callback_add(p, PROMISE_EVENT_SUCCESS, _success, data)
eo_promise_commit(p) // steals the ref


// or:
p = promise_function(obj)
eo_event_callback_add(p, PROGRESS_EVENT, _progress, data)
eo_event_callback_add(p, PROMISE_EVENT_SUCCESS, _success, data)
eo_event_callback_add(p, PROMISE_EVENT_SUCCESS, _success_watcher, data)
eo_event_callback_add(p, PROMISE_CANCEL_SUCCESS, _canceled, data)
eo_wref_add(p, &p2)
eo_data_key_set(p, "my data", stuff_that_i_need)
eo_promise_commit(p)

etc...


_race and _all could be implemented in Eo.Promise, and would make the _all
promise get an extra ref on the sub promise.


And then the eo event callback data is "data", the event->info is the value
(void* anyway).

Internally, all we need to make sure is that all the callbacks will be
called (error or success), and the promise object can't be deleted until
then.
Also need to ensure that we unref() the promise object after it called its
callback (this can be done in each promise implementation - no infra).

What happens if cancel() is called during a success callback? Will the
cancel or error cbs be called? Anyway this is a tricky situation, similar
to eo_del() during a callback.



Now, if you forget about Eo, Eina, ... and go back to C++, you will agree
that anything is an object. A promise would also be an object, an instance
of a class. Why would it be any different with our object model?


So, yeah, still not convinced we need a different event signature, a
different ref/unref system (where, as seen above, we can manipulate objects
of which we don't own any ref), and lose on the way all the fancy features
that eo provides.


Best regards,

-- 
Jean-Philippe André
------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity 
planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to