From: Tom H. <to...@os...> - 2016-09-28 12:53:22
|
On 28/09/16 13:42, Tom Hacohen wrote: > 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. > One clarification: the example above does not handle reuse of promises, that is, use the result of file_set() in both race and all (for example). This, I assume, is a more rare occasion. However, there's a simple solution to that too. You would explicitly create a new promise that supports multiple "then/catch". This gets more similar to the original promise proposal, that just used basic structures and was passed as a parameter to some functions. This may be the better solution after all. I'm writing another email to clarify that stance. > > 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. |