Yes I do think the async keyword to start execution without waiting is an improvement, but would still like to have cancel, thread control, timeout, and improved debugging.
-- Howard. On 28 August 2017 at 13:21, Jonathan Hull <[email protected]> wrote: > What do you think of the idea that several of us have been proposing on > another thread? In addition to being able to place ‘await' before an > asynchronous function, you could instead write ‘async’ which would simply > allow you to defer calling await (presumably until you need to await > multiple items at once). You would be required by the compiler to call > ‘await’ before being able to access the resulting value. > > let a = async longCalculationA() > let b = async longCalculationB() //b doesn’t wait for a to complete before > starting > let c = async longCalculationC() //c doesn’t wait for a or b > let result = await combineCalculations(a: a, b: b, c: c) //waits until a, > b, and c are all available > > I think this would give us 80% of the value of futures, but with added > benefits: > > • *It* *allows* *optimizations which futures do not* - One of swift’s > core goals is to have the resulting program be as fast/performant as > possible. The compiler has a lot of freedom here to optimize as it sees > fit, because it doesn’t have to create a programmer inspectable object. > The above could be implemented by the compiler behind the scenes using some > sort of future, but it could also just combine the continuation blocks in a > different way. It can provide different optimizations in different > situations. > > • *It is forward compatible* - Even if we just implement this by creating > internal futures, because we don’t expose those details, that > implementation can be changed at any time without involving evolution. > > • *It works with any async function* - Futures have a different type, and > so any function returning a future (especially in a chain of returns) must > explicitly return Future<Type>. The proposal above returns the normal type > (with a compiler annotation forcing await to be called before it is used). > As a result ‘async’ can be used anywhere ‘await’ can be used, even in a > chain of ‘async’ returns. The guarantee we are making is that the result > will not be used without calling ‘await’. > > • *It may make actual futures more efficient* - None of the points above > are arguing against having futures in Swift. I want them in the standard > library! With the above as a base, it should be fairly simple to build > futures as a framework with all of introspection and cancellation ability > that implies. Those futures should also gain some of the optimizations of > that base as a result (especially when there are intermediate stages to a > long calculation, etc…). > > Thanks, > Jon > > On Aug 27, 2017, at 7:22 PM, Adam Kemp via swift-evolution < > [email protected]> wrote: > > As has been explained, futures can be built on top of async/await (or the > other way around). You can have the best of both worlds. We are not losing > anything by having this feature. It would be a huge improvement to have > this as an option. > > However, using futures correctly requires more nested closures than you > have shown in your examples to avoid blocking any threads. That's why > you're not seeing the advantage to async/await. You're comparing examples > that have very different behaviors. > > That said, I have also expressed my opinion that it is better to build > async/await on top of futures rather than the other way around. I believe > it is more powerful and cleaner to make async/await work with any arbitrary > future type (via a protocol). The alternative (building futures on top of > async/await) requires more code when the two are mixed. I very much prefer > how it's done in C#, where you can freely mix the two models without having > to resort to ad-hoc wrappers, and you can use async/await with any futures > implementation you might already be using. > > I really think we should be having more discussion about the tradeoffs > between those two approaches, and I'm concerned that some of the opinions > about how C# does it are not based on a clear and accurate understanding of > how it actually works in that language. > > -- > Adam Kemp > > On Aug 27, 2017, at 6:02 PM, Howard Lovatt <[email protected]> > wrote: > > The async/await is very similar to the proposed Future (as I posed > earlier) with regard to completion-handler code, they both re-write the > imported completion-handler function using a closure, the relevant sentence > from the Async Proposal is: > > "Under the hood, the compiler rewrites this code using nested closures ..." > > > Unlike the proposed future code the async code is not naturally parallel, > in the running example the following lines from the async code are run in > series, i.e. await blocks: > > let dataResource = await loadWebResource("dataprofile.txt") > let imageResource = await loadWebResource("imagedata.dat") > > The equivalent lines using the proposed Future: > > let dataResource = loadWebResource("dataprofile.txt") > let imageResource = loadWebResource("imagedata.dat") > > Run in parallel and therefore are potentially faster assuming that > resources, like cores and IO, are available. > > Therefore you would be better using a Future than an async, so why provide > an async unless you can make a convincing argument that it allows you to > write a better future? > > -- Howard. > > On 28 August 2017 at 09:59, Adam Kemp <[email protected]> wrote: > >> This example still has nested closures (to create a Future), and still >> relies on a synchronous get method that will block a thread. Async/await >> does not require blocking any threads. >> >> I’m definitely a fan of futures, but this example isn’t even a good >> example of using futures. If you’re using a synchronous get method then >> you’re not using futures properly. They’re supposed to make it easy to >> avoid writing blocking code. This example just does the blocking call on >> some other thread. >> >> Doing it properly would show the benefits of async/await because it would >> require more nesting and more complex error handling. By simplifying the >> code you’ve made a comparison between proper asynchronous code (with >> async/await) and improper asynchronous code (your example). >> >> That tendency to want to just block a thread to make it easier is exactly >> why async/await is so valuable. You get simple code while still doing it >> correctly. >> >> -- >> Adam Kemp >> >> On Aug 27, 2017, at 4:00 PM, Howard Lovatt via swift-evolution < >> [email protected]> wrote: >> >> The running example used in the white paper coded using a Future is: >> >> func processImageData1() -> Future<Image> { >> return AsynchronousFuture { _ -> Image in >> let dataResource = loadWebResource("dataprofile.txt") // >> dataResource and imageResource run in parallel. >> let imageResource = loadWebResource("imagedata.dat") >> let imageTmp = decodeImage(dataResource.get ?? >> Resource(path: "Default data resource or prompt user"), imageResource.get >> ?? Resource(path: "Default image resource or prompt user")) >> let imageResult = dewarpAndCleanupImage(imageTmp.get ?? >> Image(dataPath: "Default image or prompt user", imagePath: "Default image >> or prompt user")) >> return imageResult.get ?? Image(dataPath: "Default image or >> prompt user", imagePath: "Default image or prompt user") >> } >> } >> >> This also avoids the pyramid of doom; the pyramid is avoided by >> converting continuation-handlers into either a sync or future, i.e. it is >> the importer that eliminates the nesting by translating the code >> automatically. >> >> This example using Future also demonstrates three advantages of Future: >> they are naturally parallel (dataResource and imageResource lines run in >> parallel), they timeout automatically (get returns nil if the Future has >> taken too long), and if there is a failure (for any reason including >> timeout) it provides a method of either detecting the failure or providing >> a default (get returns nil on failure). >> >> There are a three of other advantages a Future has that this example >> doesn’t show: control over which thread the Future runs on, Futures can be >> cancelled, and debugging information is available. >> >> You could imagine `async` as a syntax sugar for Future, e.g. the above >> Future example could be: >> >> func processImageData1() async -> Image { >> let dataResource = loadWebResource("dataprofile.txt") // >> dataResource and imageResource run in parallel. >> let imageResource = loadWebResource("imagedata.dat") >> let imageTmp = decodeImage(dataResource.get ?? Resource(path: >> "Default data resource or prompt user"), imageResource.get ?? >> Resource(path: "Default image resource or prompt user")) >> let imageResult = dewarpAndCleanupImage(imageTmp.get ?? >> Image(dataPath: "Default image or prompt user", imagePath: "Default image >> or prompt user")) >> return imageResult.get ?? Image(dataPath: "Default image or prompt >> user", imagePath: "Default image or prompt user") >> } >> >> Since an async is sugar for Future the async runs as soon as it is >> created (as soon as the underlying Future is created) and get returns an >> optional (also cancel and status would be still be present). Then if you >> want control over threads and timeout they could be arguments to async: >> >> func processImageData1() async(queue: DispatchQueue.main, timeout: >> .seconds(5)) -> Image { ... } >> >> On Sat, 26 Aug 2017 at 11:00 pm, Florent Vilmart <[email protected]> >> wrote: >> >>> Howard, with async / await, the code is flat and you don’t have to >>> unowned/weak self to prevent hideous cycles in the callbacks. >>> Futures can’t do that >>> >>> On Aug 26, 2017, 04:37 -0400, Goffredo Marocchi via swift-evolution < >>> [email protected]>, wrote: >>> >>> With both he now built in promises in Node8 as well as libraries like >>> Bluebird there was ample time to evaluate them and convert/auto convert at >>> times libraries that loved callback pyramids of doom when the flow grows >>> complex into promise based chains. Converting to Promises seems magical for >>> the simple case, but can quickly descend in hard to follow flows and hard >>> to debug errors when you move to non trivial multi path scenarios. JS is >>> now solving it with their implementation of async/await, but the point is >>> that without the full picture any single solution would break horribly in >>> real life scenarios. >>> >>> Sent from my iPhone >>> >>> On 26 Aug 2017, at 06:27, Howard Lovatt via swift-evolution < >>> [email protected]> wrote: >>> >>> My argument goes like this: >>> >>> 1. You don't need async/await to write a powerful future type; you can >>> use the underlying threads just as well, i.e. future with async/await is no >>> better than future without. >>> >>> 2. Since future is more powerful, thread control, cancel, and timeout, >>> people should be encouraged to use this; instead because async/await are >>> language features they will be presumed, incorrectly, to be the best way, >>> consequently people will get into trouble with deadlocks because they don't >>> have control. >>> >>> 3. async/await will require some engineering work and will at best >>> make a mild syntax improvement and at worst lead to deadlocks, therefore >>> they just don't carry their weight in terms of useful additions to Swift. >>> >>> Therefore, save some engineering effort and just provide a future >>> library. >>> >>> To turn the question round another way, in two forms: >>> >>> 1. What can async/wait do that a future can't? >>> >>> 2. How will future be improved if async/await is added? >>> >>> >>> -- Howard. >>> >>> On 26 August 2017 at 02:23, Joe Groff <[email protected]> wrote: >>> >>>> >>>> On Aug 25, 2017, at 12:34 AM, Howard Lovatt <[email protected]> >>>> wrote: >>>> >>>> In particular a future that is cancellable is more powerful that the >>>> proposed async/await. >>>> >>>> >>>> It's not more powerful; the features are to some degree disjoint. You >>>> can build a Future abstraction and then use async/await to sugar code that >>>> threads computation through futures. Getting back to Jakob's example, >>>> someone (maybe the Clang importer, maybe Apple's framework developers in an >>>> overlay) will still need to build infrastructure on top of IBActions and >>>> other currently ad-hoc signalling mechanisms to integrate them into a more >>>> expressive coordination framework. >>>> >>>> -Joe >>>> >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >>> -- >> -- Howard. >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
