Hi,
Here's a question about promise chaining. C being what it is, it's harder to define a series like p.then().then() than it is in JS. And I can't find any good example in EFL code. Let's consider an abstract chain that I'll define as "download, unzip, show". (eg. download a zip file, unzip it and set the file on an image object). All of these are async, we don't care about the result of show. I don't understand how the chain should be written: main_func(url) { Efl_Future *f1 = download_url(url); Efl_Future *f2 = efl_future_then(f1, _down_cb, ..., NULL); efl_future_then(f2, _unzip_cb, ..., image); } // So far I think we're ok void _down_cb(null, event) { Efl_Promise *next = event->info->next; Efl_Future *f3 = _async_unzip(event->infodata); efl_future_then(f3, _unzip_cb2, .., next); } // I'm already getting confused with next, f2 and f3. Something is odd. void _unzip_cb(data, event) { Image *image = data; show(image); } void _unzip_cb2(data, event) { Efl_Promise *p2 = data; efl_promise_value_set(p3, NULL, NULL); // --> calls unzip_cb } So my questions: 1. Is this above code correct? 2. (How) are we ensuring that the chain eventually resolves? 3. Couldn't this be made in a simpler way? unzip_cb2 is really just an automatic resolve of another promise/future. In unzip_cb, if I ignore "next", f2 will never come to completion. So here's a proposal: 1. Get rid of info->next. Instead: Efl_Promise *p2 = efl_promise_next(event->object); That way, EFL knows that the developer has not ignored the promise. The developer must then call efl_promise_value/error_set at some point, sync or async. If the callback doesn't call efl_promise_next, EFL knows that the "next" promise will never come to completion, ever. In that case, EFL automatically calls efl_promise_value_set(next, NULL, NULL) to keep walking the chain. (Another idea is to instead cancel it). According to [ https://promisesaplus.com/ ], if onResolve is not a function (success_cb is NULL), then p2 is fullfilled with the same value as p1. So I guess we would just call _unzip_cb directly in the above example. Without efl_promise_next() the callback must always handle "next". Failure to do so will break all chains, and leak. The value of "next" can be set inside _efl_loop_future_success. 2. (raster's idea) Get rid of event->info Similarly, use efl_promise_value_get() instead of event->info->value. That way we can implement stealing with efl_promise_value_steal(&val, &freefunc) and keep the symmetry with value_get(). In that case, efl_ref(promise) can be used to keep a value alive for as long as you want. It's just a storage object. [if not eo, then promise_ref, whatever] Any weak ref by efl_promise_use probably needs to be reset to NULL after the success/fail callback. 3. multiple then, race, all order of operations WIth steal, and any kind of cleanup callback, the order of operations is crucial. Is it well defined? Example: f1 = function(); efl_future_then(f1, _then1, ...); efl_future_then(f1, _then2, ...); efl_future_then(f1, _then3, ...); // then1, then2, then3 MUST be called in this order (I think) f2 = function(); efl_future_then(efl_future_all(f1, f2), _then4); efl_future_then(f2, _then5, ...); // will it be _then4, _then5 or _then5, _then4? // same question for race // I believe the implementation is fine here, but not many docs/tests/uses :( Thoughts? Is the above OK or completely off track? PS: Sorry this mail became longer than I thought at first :-/ -- Jean-Philippe André ------------------------------------------------------------------------------ _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel