I think the biggest tradeoff is clearer when you look at the examples from the proposal where futures are built on top of async/await:
func processImageData1a() async -> Image { let dataResource = Future { await loadWebResource("dataprofile.txt") } let imageResource = Future { await loadWebResource("imagedata.dat") } // ... other stuff can go here to cover load latency... let imageTmp = await decodeImage(dataResource.get(), imageResource.get()) let imageResult = await dewarpAndCleanupImage(imageTmp) return imageResult } With this approach you have to wrap each call site to create a future. Compare to this: func processImageData1a() -> Future<Image> { let dataResourceFuture = loadWebResource("dataprofile.txt”); let imageResourceFuture = loadWebResource("imagedata.dat”); // ... other stuff can go here to cover load latency... let imageTmp = await decodeImage(await dataResourceFuture, await imageResourceFuture) let imageResult = await dewarpAndCleanupImage(imageTmp) return imageResult } Here, not only are the explicit wrappers gone, but this function itself can be used with either await or as a future. You get both options with one implementation. As I’ve mentioned before, C#’s implementation is not tied to any one particular futures implementation. The Task type is commonly used, but async/await does not directly depend on Task. Instead it works with any return type that meets certain requirements (detailed here: https://blogs.msdn.microsoft.com/pfxteam/2011/01/13/await-anything/ <https://blogs.msdn.microsoft.com/pfxteam/2011/01/13/await-anything/>). Swift could do this using a protocol, which can be retroactively applied using an extension. Obviously for this to be useful we would need some kind of existing future implementation, but at least we wouldn’t be tied to any particular one. That would mean library maintainers who have already been using their own futures implementations could quickly adopt async/await in their code without having to rewrite their futures library or throw wrappers around every usage of async/await. They could just adopt a protocol (using an extension, even) and get async/await support for free. The downside is that this feature would be specific to the async/await use case rather than a generic coroutine implementation (i.e., there would have to be a separate compiler transform for yield return). It’s not clear to me why it should be a goal to have just one generic coroutine feature. The real-world usages of async/await and yield return are different enough that I’m not convinced we could have a single compiler feature that meets the needs of both cleanly. > On Aug 27, 2017, at 7:35 PM, Florent Vilmart <flor...@flovilmart.com> wrote: > > Adam, you’re completely right, languages as c# and JS have been through the > path before, (callback, Promises , async/await) I believe Chris’s goal it to > avoid building a promise implementation and go straight to a coroutines > model, which is more deeply integrated with the compiler. I don’t see a > particular trade off, pursuing that route, and the main benefit is that > coroutines can power any asynchronous metaphor (Signals, Streams, Futures, > Promises etc...) which is not true of Futures so i would tend to think that > for the long run, and to maximize usability, async/await/yield would probably > be the way to go. > > On Aug 27, 2017, 22:22 -0400, Adam Kemp <adam.k...@apple.com>, 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 <howard.lov...@gmail.com >> <mailto:howard.lov...@gmail.com>> 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 <adam.k...@apple.com >>> <mailto:adam.k...@apple.com>> 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 >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 <flor...@flovilmart.com >>>> <mailto:flor...@flovilmart.com>> 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 >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>, 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 >>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 <jgr...@apple.com >>>>>> <mailto:jgr...@apple.com>> wrote: >>>>>> >>>>>>> On Aug 25, 2017, at 12:34 AM, Howard Lovatt <howard.lov...@gmail.com >>>>>>> <mailto:howard.lov...@gmail.com>> 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 >>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>> >>>> -- >>>> -- Howard. >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution