Below is the example I envisioned when Pontus revealed the Promise-based HTTP stuff. It will fetch all images referenced by a web page, nice and neat. The good thing about futures is that you’ll either get success or fail in the end, nothing in-between (if implemented correctly) (yeah, I know that you already like it, so I’m not really educating you.. :) )
Regarding “then” – maybe we can do it “The Pike Way” and add such a method too... It shouldn’t really conflict with the other stuff. int main(int argc, array argv) { string base_url = "http://www.cnn.com/"; Standards.URI base_uri = Standards.URI (base_url); Concurrent.Future img_futures = Protocols.HTTP.Promise.get_url (base_url) ->flat_map (lambda (Protocols.HTTP.Promise.Success res) // flat_map maps the result of the Future returned by // get_url (.Success) to a new Future. { array(string) img_urls = ({}); Parser.HTML p = Parser.HTML(); p->add_tag ("img", lambda (Parser.HTML p, mapping args) { if (string src = args["src"]) { if (has_prefix (src, "http")) { img_urls += ({ Standards.URI (src, base_uri) }); } } }); p->finish (res->data)->read(); // img_futures will contain a Future for each URL in // img_urls (since that's what // Protocols.HTTP.Promise.get_url returns). array(Concurrent.Future) img_futures = map (img_urls, Protocols.HTTP.Promise.get_url); // Concurrent.results wraps an array of Futures in a // new Future. When all the wrapped Futures have // succeeeded, the new future will succeed with an // array of the wrapped values as its result. return Concurrent.results (img_futures); }) ->map (lambda (array(Protocols.HTTP.Promise.Success) results) // map simply maps the result of the Future to a plain // value (no new Future.) We'll get an array of // Protocols.HTTP.Promise.Success objects. { return results->data; }); img_futures->on_success (lambda(array(string) img_data) // img_data is an array of image data strings. { werror ("Got a bunch of data: %O\n", map (img_data, sizeof)); }); img_futures->on_failure (lambda (mixed err) { werror ("Failed: %O\n", err); }); return -1; } > On 25 May 2016, at 14:10 , Marcus Agehall (nu med K-märkt fastighet och ny > elcentral) @ Pike (-) developers forum <10...@lyskom.lysator.liu.se> wrote: > > From looking at the module, that was far from obvious if you ask > me. Even though the docs says just that. > > I'm not sure I see how having separate methods here will give us > better typing, but maybe it does. > > My opinion is that we should try to have an API that is as similar as > possible to others and if that isn't possible or desirable, we should > provide examples on how to use our API as part of the docs. > >> Regarding chaining â I think youâre looking for Future.map and >> Future.flat_map. Calling map in a Future will return a new Future that will >> be fulfilled with the result of the callback provided to map. flat_map >> allows the callback to return a new Future, which will be chained with the >> Future initially returned by flat_map. >> >> Future f = do_async_stuff(); >> f->flat_map (lambda (string result) { return >> do_more_async_stuff_returning_a_future(result); })->on_success (lambda >> (string final_result) { }); >> f->map (lambda (string result) { return reverse (result); })->on_success >> (lambda (string final_result) { }); >> >> Separating it to separate methods is good when you care about typing, but JS >> doesnât care too much about typing so they combined everything into >> âthenâ in the ES6 Promise implementation (this is my personal >> reflection, I might be wrong ;) ) >> >> /Marty >> >>> On 22 May 2016, at 16:40 , Marcus Agehall (nu med K-märkt fastighet och ny >>> elcentral) @ Pike (-) developers forum <10...@lyskom.lysator.liu.se> wrote: >>> >>> I have spent some time looking at the new stuff in Concurrent.pmod >>> that Grubba has added to 8.1. Mostly it is code relating to the >>> concept of Promises and Futures which are very popular amongst >>> JavaScript people these days. >>> >>> I have noted that there seems to be some rather striking differences >>> between how JavaScript treats promises and how Pike does it. I'm not >>> sure this is a good thing(tm) and therefore I'd like to bring this up >>> before 8.1 stabilizes. >>> >>> In Pike, we have two methods that register callback functions, >>> Future.on_success() and Future.on_failure() as opposed to JS where >>> only one method, then(), is used to register both callbacks. I don't >>> mind having two different methods, but for easier transition between >>> the two languages (i.e. for people writing both client-side and >>> server-side code) having the same API would probably help. >>> >>> A bigger problem imho is the difference in how promises are actually >>> resolved. In JavaScript, the return value of then() is always a *new* >>> promise which then allows for chaining. In Pike, we return the same >>> promise object. This means that code like >>> >>> my_promise->on_success(foo)->on_success(bar) >>> >>> in Pike would result only in a call to bar() once my_promise is >>> resolved whereas in JavaScript, foo() would be called and it's return >>> value would be the input to bar in a new promise. >>> >>> The whole creation of promises is also somewhat awkward in Pike. In >>> JS, you simply pass a callback that will do all the work and that will >>> recieve a success callback and a failure callback as arguments and off >>> you go. In Pike, I'm not sure what the best way to do it is. >>> >>> I really like the idea of having promises in Pike, but would it not be >>> much better if we tried to implement an API more similar to what the >>> JS folks are used to? At least I think so... >>> >>> Here are three links to good resources I've found regarding promises >>> in JS. I'm sure there are a ton of others as well. >>> >>> https://promisesaplus.com/ >>> http://www.mattgreer.org/articles/promises-in-wicked-detail/ >>> http://bluebirdjs.com/docs/api-reference.html >> >>