From: Tom H. <to...@os...> - 2016-09-28 12:42:54
|
On 21/09/16 03:35, Felipe Magno de Almeida wrote: > On Sun, Sep 18, 2016 at 3:35 AM, Davide Andreoli <da...@gu...> wrote: >> 2016-09-18 4:30 GMT+02:00 Felipe Magno de Almeida < >> fel...@gm...>: >>> On Sep 17, 2016 3:53 AM, "Davide Andreoli" <da...@gu...> wrote: > > [snip] > >>> The problem with callbacks is not difficult to implement, but difficult to >>> free the void* data. It needs two function pointers and the void* data to >>> implement correctly and generally. Not that I'm against per se, but >>> lifetime is the real problem. >> >> Indeed the lifetime of the *void data is the trickiest part, a free_data_cb >> seems to me the most "correct" way to handle this, not only for bindings >> but also for C code. >> >> Can you explain me how promises solve this problem? where the user is >> expected to free the *data in C? in both the success/failure callbacks? > > Promises are not generic, so their lifetime is known. The user frees it in > success/failure callback, yes. This is a bias to the promise solution, a bias that has been around ever since promises were introduced. Davide's idea could be implemented just as well if given the same assumptions. At the moment we have promises, they are manually handled by bindings and they, as you said, are not generic. More specifically, they die after success/failure is called. If you follow the same restrictions, you can easily just add a callback function and a data pointer to APIs. The data will be released by the caller after the call. Bindings can easily deal with that. And to put this in a more generic sense, we could allow "one-time" callbacks (of a shared signature) in Eolian to solve all of this class of problems without the overhead of promises. We could make the "event info" (I'd keep the same callback signature for consistency) of this callback indicate if it's been successful or not (i.e. then/catch) which will also let you easily create race/all. A code example (for race, all is almost identical): // API we provide struct { func: cb; void *: data; } promise_cb; typedef Promise_Race; // This needs a better name, as it's shared with all. promise_cb *promise_cb_get(Promise_Race *promise); // user code: Promise_Race *race = race_add(); file_set(obj, promise_cb_get(race)); image_load(obj, promise_cb_get(race)); race_then({.func = user_race_finished_cb, .data = user_data}); Race is then a very lightweight structure that needs no handling. This comes back to what I've been saying for a year, there are many more ways to solve this problem, and if you ask me, most of which are much cleaner than promises, or at least the suggested handling. I like this one much better than I like the previously proposed promises solution. -- Tom. |