Okay, that's an interesting proposal. I'm not qualified to judge how big of a win the compiler optimizations would be there; I'm a little skeptical, but I admit a lack of expertise there. It seems like it's not essential to the core 'async/await' proposal, though; it could be added later with no source breakage, and in the meantime we can accomplish most of the same behavior through an explicit Future type. I think it makes more sense to consider the base proposal before adding more complexity to it.
-BJ > On Sep 3, 2017, at 10:15 PM, Jonathan Hull <[email protected]> wrote: > > >> On Sep 3, 2017, at 7:35 PM, BJ Homer <[email protected]> wrote: >> >> Jonathan, >> >> You've mentioned the desire to have 'async' defer calling 'await', but I >> haven't seen a detailed design yet. > Oh, we discussed it awhile back on a few other threads. I am happy to help > write up a more formal/detailed design if there is enough interest... > >> For example, is the following code valid? >> >> let image = async fetchImage() >> let image2 = async fetchImage() >> let deferredThings = [image1, image2] >> >> If so, what is the type of 'deferredThings'? And how does it not count as >> 'using' the values. > > No this code is not valid. You would need to ‘await’ both image 1 & 2 before > they could be put in an array or transferred to another variable. You could > combine the ‘await’s though (similar to try): > > let image = async fetchImage() > let image2 = async fetchImage() > let deferredThings = await [image1, image2] > > > Note: You can return something which is deferred from an async function > without awaiting though... > > >> If the above code is not valid, how is this situation better than the >> suggested use of a Future type to allow concurrent async requests? >> >> let future1 = Future { await fetchImage() } >> let future2 = Future { await fetchImage() } >> let deferredThings = [future1, future2] >> >> Note that in this example, 'deferredThings' has a concrete type, and we can >> inspect its values. > > It isn’t meant to be used instead of Futures (though you may not need to > reach for them as often), it is a much lower-level construct which would be > used as a building block for things like futures (and other concurrency > constructs). > > Because there is no way for the programmer to get at the thing being > ‘await’ed (or any representation of it) without awaiting on it, and it can’t > escape the context, it gives the compiler some extra guarantees that it can > use to optimize things behind the scenes. Even if the compiler just ends up > creating a future behind the scenes, that implementation is completely hidden > to the programmer, and can be updated/changed at any time by the compiler > team without involving evolution. > > Let’s say at some point down the road as part of the actor work, the compiler > ends up getting some visibility into how actor queues will be coalesced… Then > it can use that knowledge to reorganize the code above to be more efficient. > For example, if it knows that the part of the calls to fetchImage() will be > serialized by an actor, it can just make that part synchronous and avoid the > asynchronous overhead. If we had baked in everything at the low-level to use > future objects, we wouldn’t be able to make that optimization. > > There are 2 big results from this: > > 1) It gives us the ability to easily start several things behind the scenes > and then await the group of them finishing > > 2) Our implementation of Futures (and other constructs) can potentially take > advantage of the compiler optimizations by using this beneath the hood. > > > The first point is huge for me. This is an extremely common thing to want in > real-world code, but it usually requires a bunch of complex (sometimes > error-prone) machinery to actually pull off. There is often wasted overhead > as well. I like that I can do it here in a very natural and lightweight way. > (Futures also simplify this problem a great deal, but I wouldn’t really call > them lightweight). > > >> You keep bringing up this suggestion, so I must be missing something, but it >> seems to me that your suggestion is covered by Futures. Why is calling with >> 'async' better? > > As I said above, I think this will help our Futures be much more efficient > when we build them, but there are also some advantages of having this as an > option and not just using Futures for everything. > > Mainly, futures require a different return type, and they require > boxing/unboxing. To chain futures, each link in the chain has to be > future-aware… and each link can only be used with futures (i.e. the return > type is Future<MyType>). There are a lot of cases where I am boxing just to > unbox and re-box. Most of that is fine as long as the framework was built > with it in mind, but it doesn’t work as well if I want to add the > functionality post-hoc. > > With ‘async’ being used to defer ‘await’, it just works on any function which > can be awaited. Further, it can be chained naturally through any number of > async functions. I showed this in another thread, but if you think through > what happens when you return something which still needs to be awaited, you > see that that state is naturally passed along with it (the function was > either called with ‘await’ or ‘async’, and thus the return value is either > awaited on, or the result picks up the compiler marking from ‘async’ showing > it still needs to be awaited). Because there is no (visible) boxing, you > don’t have to worry about monads, etc… > > It basically nests in the same way that try/throws nests, and we already have > to do that for async/await anyway… so it is a lot of win for very little > additional complexity (at least on the usage side). > > Thanks, > Jon > > > >> -BJ >> >>> On Sep 3, 2017, at 6:01 PM, Jonathan Hull via swift-evolution >>> <[email protected]> wrote: >>> >>> >>>>> On Sep 3, 2017, at 9:04 AM, Chris Lattner via swift-evolution >>>>> <[email protected]> wrote: >>>>>> On Sep 3, 2017, at 4:00 AM, David Hart <[email protected]> wrote: >>>>>> Please don’t read too much into the beginAsync API. It is merely a >>>>>> strawman, and intended to be a low-level API that higher level >>>>>> abstractions (like a decent futures API) can be built on top of. I >>>>>> think it is important to have some sort of primitive low-level API that >>>>>> is independent of higher level abstractions like Futures. >>>>>> >>>>>> This is all a way of saying “yes, having something like you propose >>>>>> makes sense” but that it should be part of the Futures API, which is >>>>>> outside the scope of the async/await proposal. >>>>> >>>>> But it would be nice for all high-level APIs that conform to a Awaitable >>>>> protocol to be used with await without having to reach for a get property >>>>> or something similar everytime. >>>> >>>> The futures API that is outlined in the proposal is just an example, it >>>> isn’t a concrete pitch for a specific API. There are a bunch of >>>> improvements that can (and should) be made to it, it is just that a >>>> futures API should be the subject of a follow-on proposal to the basic >>>> async/await mechanics. >>> >>> Would it be possible to have the manifesto be a series of proposals then? >>> I really think it is important for us to look at how all of these things >>> fit together. I agree that async/await should come first, but looking at >>> how concrete things like Futures would work may help to inform the design >>> of async/await. We should do the back-propigation in our design before >>> anything is locked in... >>> >>> The thing I would most like to see as a quick follow-on to async/await is >>> the ability to use the ‘async’ keyword to defer ‘await’. This feels very >>> natural, is highly optimizable by the compiler, and it allows for a lot of >>> very common use-cases which are not covered well by pure async/await. I >>> think it would have a large impact on the eventual design/implementation of >>> futures (and at least some impact on the design of async/await). >>> >>> Thanks, >>> Jon >>> _______________________________________________ >>> 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
