On Wed, Jan 3, 2018 at 1:07 PM, Andrew Williams <a...@andywilliams.me> wrote: > Then surely the we are missing something in eina to get the main loop > scheduler? > Moving this code into the efl namespace seems misleading if the intent is > that it would not be part of our bindings. > Eina is, if I understand it, there for the C implementation specifics...
answered in IRC, but doing again so it's archived together with this email: according to the promise/future specifications, the future callback must be dispatched "from a clean context", that is, when there is only "platform code running", in our case, when using the main loop: it's straight from the main loop. in JavaScript, people often implement that using setTimeout(0, futureDispatcher). in our case, it is (was?) implemented using ecore_event, such as other primitives (ecore_job, etc). however, since eina knows nothing about ecore/main loop, we can't find a main loop and register those in order to get the clean context to dispatch the future callback. to address that, Eina_Future_Scheduler exists. It is the structure that must be filled and given to eina_promise_new() so the promise and associated future chain uses when a future must be dispatched from that clean context. It's very similar to "ecore_event_add()" (Eina_Future_Scheduler->schedule()) and "ecore_event_del()" (Eina_Future_Scheduler->recall()). Since this is tied to a main loop instance, it's bound to Efl.Loop, which keeps a per-instance singleton that can be retrieved with Efl.Loop.future_scheduler_get(). This is a method since it's touching the object internals, which register the pending futures, destroying them if the main loop finishes (loop is deleted). However this method was not exposed in efl_loop.eo because it was meant to be "C-only", that is, shouldn't be automatically exposed by bindings that uses eolian to generate wrappers. There are no method attributes to flag methods as "C-only". To achieve this effect other EFL, including Eo itself, declares stuff in ".h" but not ".eo" files, see https://git.enlightenment.org/core/efl.git/tree/src/lib/eo/Eo.h C users have no way, they must use this method (efl_loop_future_scheduler_get()) and eina_promise_new() directly, if they want to create new promises. --> Note it's not that common to create new promises! Usually you chain from one (ie: efl_loop_timeout(), efl_loop_idle(), efl_loop_job()...) just adding new futures to its execution chain. In other circumstances you want to just dispatch a known value or error using the promise/future infrastructure, in these cases you use eina_future_resolved(scheduler, value) or eina_future_rejected(scheduler, error). Bindings, on the other hand, have two options: -> Languages with native Promise, or with a common/defacto standard library that implements one, like JavaScript/nodejs, Python, C#, C++ EFL developers using such languages shouldn't create Eina_Promise or Eina_Future, instead they should transparently use their language-native implementation which should transparently integrate with EFL. On these bindings, things like efl.loop.timeout() shouldn't return Eina.Future direct/specific wrappers. Instead they should return native "Promise" (or Future, but most implementations call it "Promise", like in JavaScript, A+/Promise...), which is itself resolved from eina_future. Consider the following PSEUDO code that a JavaScript/EFL binding would generate for efl_loop_timeout, which returns an Eina_Future: static Eina_Value _future_void_resolved(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { JS_Obj *js_promise = data; if (v.type == EINA_VALUE_TYPE_ERROR) { Eina_Error err; eina_value_error_get(&v, &err); js_promise_reject(js_promise, js_error_from_eina_error(err)); } else js_promise_resolve(js_promise, JS_Obj_Void); return v; } JS_Obj * efl_loop_timeout_wrapper(JS_Obj *wrapper, double timeout) { Efl_Loop *loop = js_obj_native_object_get(wrapper); Eina_Future *ef = efl_loop_timeout(loop, timeout); JS_Obj *js_promise = js_promise_new(); eina_future_then(ef, _future_void_resolved, js_promise); return js_promise; } That's why once old "Efl_Future" (Eo-classes) are removed q66 will change eolian to emit "Eina_Future*" for the reserved keyword "future<type>", and bindings should provide a similar tooling. For these cases there should be no reason to expose efl_loop_future_scheduler_get(). -> Languages without Promise and no major library/framework providing one For these, efl_loop_future_scheduler_get() must be exposed alongside at least one new type: Eina.Future wrapper. If the language supports closure/context, then there is no need to export Eina.Promise, just do something like JavaScript, using the signature: new Promise(loop, callback(onResolved, onRejected)); to be used as: function cb(onResolved, onRejected) { try { var value = doSomeWork(); onResolved(value); } catch (e) { onRejected(e); } } return new Promise(loop, cb); in the example above, the Promise constructor implemented in C would be calling 2 EFL functions: - efl_loop_future_scheduler_get() - eina_promise_new() And there is no need to expose efl_loop_future_scheduler_get() at all. -- 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 enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel