[Concurrency] Fixing race conditions in async/await example

In this example i think we lose clarity, just looking for the code we cant
know if this two line will run on parallel or not!
Also, image.get blocks the thread, in this case we need the await anyway!
And `async` can throws too... So the error handler can be pretty similar.

let image = async preprocessImage(downloadImage()) // These first two
lines run in parallel and I can "see" the async keyword.let text =
async translate(downloadText())await render(image: image ??
defaultImage, text: text ?? defaultText) // No blocking!

Like i said before! Today's, the proposal only lack two things over the
`Future`....
Parallel computing: Can be implemented by a third party library or a
personal one, but i don't think this is a good approach to the first
version.
Coordination: This we can wait! And why? Because coordination, can be made
in different ways, maybe is more suitable to a standard library
class/function, not a language level resource.

Also, coordination cant be applied to all variants of the runtimes in the
same way! async/await as language level works just as well with GCD as
with pthreads or another API. And coordination is a compromise that we can
make after that one.

···

Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution < swift-evolution@swift.org> escreveu:

@David,

Using the `Future` library based on GCD that I have previously posted your
example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallellet text = translate(downloadText())render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the
`Future` version handles errors.

So what advantage does async/await have over a `Future` library we can
write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution < > swift-evolution@swift.org> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution < >> swift-evolution@swift.org> wrote:

I know what the proposal said. I’m making a case that there is value in
doing it differently.

The composability of futures is valuable. Mixing and matching
async/await with futures is also valuable. The queue-returning behavior
that you can get from futures is also valuable, and building async/await on
top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the
queue-return behavior of futures if futures are built on top of async/await
instead off the other way around?

We could, but the syntax is much worse. Contrast:

*async/await built on top of Futures*

let image = preprocessImage(downloadImage())let text = translate(downloadText())
await render(image: image, text: text)

*Futures built on top of async/await*

let image = Future(downloadImage).then({ preprocessImage($0) })let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe

other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to
acknowledge that it comes with a downside as well. The problem with doing a
minimal implementation is that you can be stuck with the consequences for a
long time. I want to make sure that we’re not stuck with the consequences
of a minimal implementation that doesn’t adequately address the problems
that async/await should be addressing. I’d hate for Swift to get an
async/await that is so weak that it has to be augmented by tedious
boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support
that is completely concurrency runtime-agnostic. This proposal does not
include a new runtime model (like "actors") - it works just as well with
GCD as with pthreads or another API. Furthermore, unlike designs in other
languages, it is independent of specific coordination mechanisms, such as
futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other
coordination abstractions. There are many rational designs for futures, and
a lot of experience working with them. On the other hand, there are also
completely different coordination primitives that can be used with this
coroutine design, and incorporating them into this proposal only makes it
larger."

and

We focus on task-based concurrency abstractions commonly encountered in
client and server applications, particularly those that are highly event
driven (e.g. responding to UI events or requests from clients). This does
not attempt to be a comprehensive survey of all possible options, nor does
it attempt to solve all possible problems in the space of concurrency.
Instead, it outlines a single coherent design thread that can be built over
the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many
possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic
async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ?
dispatch_async also does not return nothing to do what you are intentend do
do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete"
concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the
ground free to make more complex implementation like Futures in another
round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But
doesn't matter now! Now we only need to is some kind of type which need to
be unwrapped using await before use. Maybe this intermediary/virtual type
can be a real thing and gain some abilities at some point! Maybe a full
Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com> >>> escreveu:

How would these anonymous types get composed? If I wanted to implement
a function that takes a collection of futures and wait on it, how would I
do that? That is, how would I implement the equivalent of C#’s Task.WhenAll
and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some
other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No
future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")

  // ... other stuff can go here to cover load latency...

  let imageTmp = await decodeImage(dataResource, imageResource) //
Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle
with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution < >>>> swift-evolution@swift.org> escreveu:

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:
await anything; - .NET Parallel Programming).
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 <florent@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.kemp@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.lovatt@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.kemp@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> 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 < >>>>>> florent@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>, 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> 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 <jgroff@apple.com> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt < >>>>>>>> howard.lovatt@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
https://lists.swift.org/mailman/listinfo/swift-evolution

--

-- Howard.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

In this example i think we lose clarity, just looking for the code we cant know if this two line will run on parallel or not!
Also, image.get blocks the thread, in this case we need the await anyway! And `async` can throws too... So the error handler can be pretty similar.

let image= asyncpreprocessImage(downloadImage()) // These first two lines run in parallel and I can "see" the async keyword.
let text= asynctranslate(downloadText())
await render(image: image ?? defaultImage,text: text ?? defaultText) // No blocking!

FWIW: I'm following the whole discussion from the start, and do support the opinion that async/await is much clear solution that proposed Futures, especially for beginners.
We need a low-level building blocks which can be used to implement Futures/Promises in libraries.
Also I really like the idea of 'async' on the caller side to have code running in parallel.

The 'async' version of func declaration is clearly saying what type it *want* to return, and 'async' modifier just saying *how* it will/can return that type('Image' in examples). So on both sides, on declaration and on caller side, we are clear what types we are working with.
Future<Type> - is mixing of what is returning and how this will be returned. Code is saying that we preprocessesImage, but actually we have Future<Image> type, no 'markers' of asynchronous code.

Also, I wonder(if I missed that in proposal/discussion, please let me know), if I have async function like

func foo() async -> Type {}

, may I want to call it synchronously? If so, what would be a solution here? I can think about something like 'sync' modifier on caller side:
let x = sync foo() // calling asynchronous function synchronously

I believe that is what Future.get is doing, no?
let future = ...
future.get() // blocks the execution, waits for the result.

Probably it is reasonable to allow just call foo() to get blocking result, just like any other 'simple' blocking funcs that we call, but this can lead to unexpected behavior as user can expect async execution.

With Futures, it seems like we can't "just" call such function and need to call .get() later:
let future = someFuncReturnsFuture() // already returns Future<Type> type

Vladimir.

···

On 29.08.2017 19:02, Wallacy via swift-evolution wrote:

Like i said before! Today's, the proposal only lack two things over the `Future`....
Parallel computing: Can be implemented by a third party library or a personal one, but i don't think this is a good approach to the first version.
Coordination: This we can wait! And why? Because coordination, can be made in different ways, maybe is more suitable to a standard library class/function, not a language level resource.

Also, coordination cant be applied to all variants of the runtimes in the same way! async/await as language level works just as well with GCD as with pthreads or another API. And coordination is a compromise that we can make after that one.

Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:

    @David,

    Using the `Future` library based on GCD that I have previously posted your
    example would be:

    let image= preprocessImage(downloadImage()) // These first two lines run in parallel
    let text= translate(downloadText())
    render(image: image.get ?? defaultImage,text: text.get ?? defaultText)

    The main difference, and I would argue an improvement, is that the `Future`
    version handles errors.

    So what advantage does async/await have over a `Future` library we can write today?

       -- Howard.

    On 29 August 2017 at 15:28, David Hart via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

        On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

        On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

            I know what the proposal said. I’m making a case that there is value in
            doing it differently.

            The composability of futures is valuable. Mixing and matching
            async/await with futures is also valuable. The queue-returning behavior
            that you can get from futures is also valuable, and building
            async/await on top of futures means async/await can get that for free.

        Why couldn't you mix and match async/await and futures and get the
        queue-return behavior of futures if futures are built on top of async/await
        instead off the other way around?

        We could, but the syntax is much worse. Contrast:

        *async/await built on top of Futures*
        *

        let image= preprocessImage(downloadImage())
        let text= translate(downloadText())
        awaitrender(image: image,text: text)

        *Futures built on top of async/await*
        *

        let image= Future(downloadImage).then({preprocessImage($0) })
        let text= Future(downloadText).then({translate($0) })
        awaitrender(image: image.get(),text: text.get())

            Maybe you don’t value those things, which is fine. But I do, and maybe
            other people do too. That’s why we’re having a discussion about it.

            It can also be valuable having a minimal implementation, but we have to
            acknowledge that it comes with a downside as well. The problem with
            doing a minimal implementation is that you can be stuck with the
            consequences for a long time. I want to make sure that we’re not stuck
            with the consequences of a minimal implementation that doesn’t
            adequately address the problems that async/await should be addressing.
            I’d hate for Swift to get an async/await that is so weak that it has to
            be augmented by tedious boilerplate code before it’s useful.

            On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com >>> <mailto:wallacyf@gmail.com>> wrote:

            We don't need to this now!

            Again: (Using proposal words)

            "It is important to understand that this is proposing compiler support
            that is completely concurrency runtime-agnostic. This proposal does
            not include a new runtime model (like "actors") - it works just as
            well with GCD as with pthreads or another API. Furthermore, unlike
            designs in other languages, it is independent of specific coordination
            mechanisms, such as futures or channels, allowing these to be built as
            library feature"

            and

            "This proposal does not formally propose a |Future| type, or any other
            coordination abstractions. There are many rational designs for
            futures, and a lot of experience working with them. On the other hand,
            there are also completely different coordination primitives that can
            be used with this coroutine design, and incorporating them into this
            proposal only makes it larger."

            and

            We focus on task-based concurrency abstractions commonly encountered
            in client and server applications, particularly those that are highly
            event driven (e.g. responding to UI events or requests from clients).
            This does not attempt to be a comprehensive survey of all possible
            options, nor does it attempt to solve all possible problems in the
            space of concurrency. Instead, it outlines a single coherent design
            thread that can be built over the span of years to incrementally drive
            Swift to further greatness.

            and

            This proposal has been kept intentionally minimal, but there are many
            possible ways to expand this in the future.

            ....

            The point is: No Future type is indeed proposed yet!

            The proposal try to include de "minimum" required to implement a basic
            async/await to solve the problem created by the GCD! (Pyramid of doom)

            The question is: How do you do the same using dispatch_async ?
            dispatch_async also does not return nothing to do what you are
            intentend do do!

            Algo, by Swift 5 manifesto, there's no compromise to make a "complete"
            concurrency model by this time!

            My intention is only make parity to dispatch_async, but also make the
            ground free to make more complex implementation like Futures in
            another round on top of this one.

            This 'async T' can be a real type in the future? Maybe will... But
            doesn't matter now! Now we only need to is some kind of type which
            need to be unwrapped using await before use. Maybe this
            intermediary/virtual type can be a real thing and gain some abilities
            at some point! Maybe a full Future type, why not?

            Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com >>> <mailto:adam.kemp@apple.com>> escreveu:

                How would these anonymous types get composed? If I wanted to
                implement a function that takes a collection of futures and wait
                on it, how would I do that? That is, how would I implement the
                equivalent of C#’s Task.WhenAll and Task.WhenAny methods?

                More generally, how do you pass one of these typeless futures to
                some other function so that we can do the waiting there?

                On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com >>>> <mailto:wallacyf@gmail.com>> wrote:

                And that's why I (and others) are suggesting:

                func processImageData1a() async -> Image {
                  let dataResource = async loadWebResource("dataprofile.txt") //
                No future type here... Just another way to call dispatch_async
                under the hood.
                  let imageResource = async loadWebResource("imagedata.dat")
                  // ... other stuff can go here to cover load latency...
                  let imageTmp = await decodeImage(dataResource,
                imageResource) // Compiles force await call here...
                  let imageResult = await dewarpAndCleanupImage(imageTmp)
                  return imageResult
                }

                And now we gain all advantages of async/await again without to
                handle with one more type.

                Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>>> escreveu:

                    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:
                    await anything; - .NET Parallel Programming).
                    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 >>>>> <florent@flovilmart.com <mailto:florent@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.kemp@apple.com >>>>> <mailto:adam.kemp@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.lovatt@gmail.com <mailto:howard.lovatt@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= awaitloadWebResource("dataprofile.txt")
                       let imageResource= awaitloadWebResource("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.kemp@apple.com >>>>>>> <mailto:adam.kemp@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 >>>>>>>> <florent@flovilmart.com >>>>>>>> <mailto:florent@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 >>>>>>>>>> <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

                                On Aug 25, 2017, at 12:34 AM, Howard >>>>>>>>>>> Lovatt <howard.lovatt@gmail.com >>>>>>>>>>> <mailto:howard.lovatt@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

                        --
                        -- Howard.
                        _______________________________________________
                        swift-evolution mailing list
                        swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        https://lists.swift.org/mailman/listinfo/swift-evolution

                    _______________________________________________
                    swift-evolution mailing list
                    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
                    https://lists.swift.org/mailman/listinfo/swift-evolution

            _______________________________________________
            swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I don’t think the examples are 100% equivalent. In your version with the Future library, preprocessImage and translate need to accept futures as argument, correct? That’s more restrictive than in my example code where async/await specifically provide sugar over then. Plus I don’t understand why you mention that the Future version handles errors when async/await also plays very nicely with errors.

···

On 29 Aug 2017, at 10:22, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

Using the `Future` library based on GCD that I have previously posted your example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallel
let text = translate(downloadText())
render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the `Future` version handles errors.

So what advantage does async/await have over a `Future` library we can write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I know what the proposal said. I’m making a case that there is value in doing it differently.

The composability of futures is valuable. Mixing and matching async/await with futures is also valuable. The queue-returning behavior that you can get from futures is also valuable, and building async/await on top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the queue-return behavior of futures if futures are built on top of async/await instead off the other way around?

We could, but the syntax is much worse. Contrast:

async/await built on top of Futures

let image = preprocessImage(downloadImage())
let text = translate(downloadText())
await render(image: image, text: text)

Futures built on top of async/await

let image = Future(downloadImage).then({ preprocessImage($0) })
let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to acknowledge that it comes with a downside as well. The problem with doing a minimal implementation is that you can be stuck with the consequences for a long time. I want to make sure that we’re not stuck with the consequences of a minimal implementation that doesn’t adequately address the problems that async/await should be addressing. I’d hate for Swift to get an async/await that is so weak that it has to be augmented by tedious boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com <mailto:wallacyf@gmail.com>> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support that is completely concurrency runtime-agnostic. This proposal does not include a new runtime model (like "actors") - it works just as well with GCD as with pthreads or another API. Furthermore, unlike designs in other languages, it is independent of specific coordination mechanisms, such as futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other coordination abstractions. There are many rational designs for futures, and a lot of experience working with them. On the other hand, there are also completely different coordination primitives that can be used with this coroutine design, and incorporating them into this proposal only makes it larger."

and

We focus on task-based concurrency abstractions commonly encountered in client and server applications, particularly those that are highly event driven (e.g. responding to UI events or requests from clients). This does not attempt to be a comprehensive survey of all possible options, nor does it attempt to solve all possible problems in the space of concurrency. Instead, it outlines a single coherent design thread that can be built over the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ? dispatch_async also does not return nothing to do what you are intentend do do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete" concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the ground free to make more complex implementation like Futures in another round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But doesn't matter now! Now we only need to is some kind of type which need to be unwrapped using await before use. Maybe this intermediary/virtual type can be a real thing and gain some abilities at some point! Maybe a full Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com <mailto:adam.kemp@apple.com>> escreveu:
How would these anonymous types get composed? If I wanted to implement a function that takes a collection of futures and wait on it, how would I do that? That is, how would I implement the equivalent of C#’s Task.WhenAll and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com <mailto:wallacyf@gmail.com>> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")
  
  // ... other stuff can go here to cover load latency...
  
  let imageTmp = await decodeImage(dataResource, imageResource) // Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:
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: await anything; - .NET Parallel Programming). 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 <florent@flovilmart.com <mailto:florent@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.kemp@apple.com <mailto:adam.kemp@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.lovatt@gmail.com <mailto:howard.lovatt@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.kemp@apple.com <mailto:adam.kemp@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 <florent@flovilmart.com <mailto:florent@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 <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@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

--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Just syntactic sugar (like `?` for Optionals) which happens to align with the async/await syntax. But you are right, the syntactic sugar should represent a type which can be represented in the language. Syntactic sugar probably only makes sense if it stands for a fixed concrete type (like Optional) which is probably a bad idea compared to C# where we can customize the concrete task type. It just has to have a GetAwaiter method.

So there is no need for such syntactic sugar and it even is a hindrance.

-Thorsten

···

Am 12.09.2017 um 21:18 schrieb Adam Kemp <adam.kemp@apple.com>:

On Sep 11, 2017, at 9:56 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

My hope would be for something along these lines:

func createDownloadTasks(for urls: [URL]) -> [async Data] {
  return urls.map { url in async downloadResource(url) }
}
func await(all tasks: [async Data]) async -> [Data] {
  return tasks.map { task in await task }
}

So that’s basically a new type with a special syntax. What is the advantage to doing it that way versus just introducing a new protocol?

@Vladimir,

Default values are a problem for await/async when combined with parallel
running because await returns a value and not an optional (unlike future's
get). Below is a more realistic code for parallel running and a default
value using async/await:

func updateImage() async {

let image: Image

async do { // Runs in parallel (async)

image = try async preprocessImage(downloadImage())

} catch {

image = defaultImage

}

let text: String

async do { // Runs in parallel (async)

text = try async translate(downloadText())

} catch {

text = defaultText

}
// This line is complicated! We want render not to block (async), but have
to await for image and text.
// Render does not throw because it always has valid input.
// If async were allowed to prevent blocking then await could not

async render(image: await image, text: await text)

}

Which I don't think reads as well as the Future version:

func updateImage() -> Future<Void> {

return AsynchronousFuture { _ -> Void in

let image = preprocessImage(downloadImage()) // Parallel, Futures are
queued on creation

let text = translate(downloadText()) // Parallel, Futures are queued on
creation

// Does not block (Futures are queued on creation), but has to wait for its
inputs (get).

render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

}

}

In addition the async/await version does not have timeout; unlike the
Future version.

Suppose that downloadImage doesn't fail, it just takes forever to download
the image. The Future version will timeout automatically and the default
image will be used. With async/await the code for downloadImage and
downloadText will have to start timers and throw if the timers timeout.
Nothing to do in the Future version, it handles timeout for you.

Neither or the above versions have cancel or control over the queue they
execute on, but both would be much easier to add to the Future version,
like timeout is much easier to add, since Futures support cancel and queue
control directly.

  -- Howard.

···

On 30 August 2017 at 02:45, Vladimir.S via swift-evolution < swift-evolution@swift.org> wrote:

On 29.08.2017 19:02, Wallacy via swift-evolution wrote:

In this example i think we lose clarity, just looking for the code we
cant know if this two line will run on parallel or not!
Also, image.get blocks the thread, in this case we need the await anyway!
And `async` can throws too... So the error handler can be pretty similar.

let image= asyncpreprocessImage(downloadImage()) // These first two
lines run in parallel and I can "see" the async keyword.
let text= asynctranslate(downloadText())
await render(image: image ?? defaultImage,text: text ?? defaultText) //
No blocking!

FWIW: I'm following the whole discussion from the start, and do support
the opinion that async/await is much clear solution that proposed Futures,
especially for beginners.
We need a low-level building blocks which can be used to implement
Futures/Promises in libraries.
Also I really like the idea of 'async' on the caller side to have code
running in parallel.

The 'async' version of func declaration is clearly saying what type it
*want* to return, and 'async' modifier just saying *how* it will/can return
that type('Image' in examples). So on both sides, on declaration and on
caller side, we are clear what types we are working with.
Future<Type> - is mixing of what is returning and how this will be
returned. Code is saying that we preprocessesImage, but actually we have
Future<Image> type, no 'markers' of asynchronous code.

Also, I wonder(if I missed that in proposal/discussion, please let me
know), if I have async function like

func foo() async -> Type {}

, may I want to call it synchronously? If so, what would be a solution
here? I can think about something like 'sync' modifier on caller side:
let x = sync foo() // calling asynchronous function synchronously

I believe that is what Future.get is doing, no?
let future = ...
future.get() // blocks the execution, waits for the result.

Probably it is reasonable to allow just call foo() to get blocking result,
just like any other 'simple' blocking funcs that we call, but this can lead
to unexpected behavior as user can expect async execution.

With Futures, it seems like we can't "just" call such function and need to
call .get() later:
let future = someFuncReturnsFuture() // already returns Future<Type> type

Vladimir.

Like i said before! Today's, the proposal only lack two things over the
`Future`....
Parallel computing: Can be implemented by a third party library or a
personal one, but i don't think this is a good approach to the first
version.
Coordination: This we can wait! And why? Because coordination, can be
made in different ways, maybe is more suitable to a standard library
class/function, not a language level resource.

Also, coordination cant be applied to all variants of the runtimes in the
same way! async/await as language level works just as well with GCD as
with pthreads or another API. And coordination is a compromise that we can
make after that one.

Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution < >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:

    @David,

    Using the `Future` library based on GCD that I have previously posted
your
    example would be:

    let image= preprocessImage(downloadImage()) // These first two
lines run in parallel
    let text= translate(downloadText())
    render(image: image.get ?? defaultImage,text: text.get ?? defaultText)

    The main difference, and I would argue an improvement, is that the
`Future`
    version handles errors.

    So what advantage does async/await have over a `Future` library we
can write today?

       -- Howard.

    On 29 August 2017 at 15:28, David Hart via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

        On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>> wrote:

        On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>> wrote:

            I know what the proposal said. I’m making a case that there
is value in
            doing it differently.

            The composability of futures is valuable. Mixing and matching
            async/await with futures is also valuable. The
queue-returning behavior
            that you can get from futures is also valuable, and building
            async/await on top of futures means async/await can get that
for free.

        Why couldn't you mix and match async/await and futures and get
the
        queue-return behavior of futures if futures are built on top of
async/await
        instead off the other way around?

        We could, but the syntax is much worse. Contrast:

        *async/await built on top of Futures*
        *
        *

        let image= preprocessImage(downloadImage())
        let text= translate(downloadText())
        awaitrender(image: image,text: text)

        *Futures built on top of async/await*
        *
        *

        let image= Future(downloadImage).then({preprocessImage($0) })
        let text= Future(downloadText).then({translate($0) })
        awaitrender(image: image.get(),text: text.get())

            Maybe you don’t value those things, which is fine. But I do,

and maybe
            other people do too. That’s why we’re having a discussion
about it.

            It can also be valuable having a minimal implementation, but
we have to
            acknowledge that it comes with a downside as well. The
problem with
            doing a minimal implementation is that you can be stuck with
the
            consequences for a long time. I want to make sure that we’re
not stuck
            with the consequences of a minimal implementation that
doesn’t
            adequately address the problems that async/await should be
addressing.
            I’d hate for Swift to get an async/await that is so weak
that it has to
            be augmented by tedious boilerplate code before it’s useful.

            On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com >>>> <mailto:wallacyf@gmail.com>> wrote:

            We don't need to this now!

            Again: (Using proposal words)

            "It is important to understand that this is proposing
compiler support
            that is completely concurrency runtime-agnostic. This
proposal does
            not include a new runtime model (like "actors") - it works
just as
            well with GCD as with pthreads or another API. Furthermore,
unlike
            designs in other languages, it is independent of specific
coordination
            mechanisms, such as futures or channels, allowing these to
be built as
            library feature"

            and

            "This proposal does not formally propose a |Future| type,
or any other
            coordination abstractions. There are many rational designs
for
            futures, and a lot of experience working with them. On the
other hand,
            there are also completely different coordination primitives
that can
            be used with this coroutine design, and incorporating them
into this
            proposal only makes it larger."

            and

            We focus on task-based concurrency abstractions commonly
encountered
            in client and server applications, particularly those that
are highly
            event driven (e.g. responding to UI events or requests from
clients).
            This does not attempt to be a comprehensive survey of all
possible
            options, nor does it attempt to solve all possible problems
in the
            space of concurrency. Instead, it outlines a single
coherent design
            thread that can be built over the span of years to
incrementally drive
            Swift to further greatness.

            and

            This proposal has been kept intentionally minimal, but
there are many
            possible ways to expand this in the future.

            ....

            The point is: No Future type is indeed proposed yet!

            The proposal try to include de "minimum" required to
implement a basic
            async/await to solve the problem created by the GCD!
(Pyramid of doom)

            The question is: How do you do the same using
dispatch_async ?
            dispatch_async also does not return nothing to do what you
are
            intentend do do!

            Algo, by Swift 5 manifesto, there's no compromise to make a
"complete"
            concurrency model by this time!

            My intention is only make parity to dispatch_async, but
also make the
            ground free to make more complex implementation like
Futures in
            another round on top of this one.

            This 'async T' can be a real type in the future? Maybe
will... But
            doesn't matter now! Now we only need to is some kind of
type which
            need to be unwrapped using await before use. Maybe this
            intermediary/virtual type can be a real thing and gain some
abilities
            at some point! Maybe a full Future type, why not?

            Em seg, 28 de ago de 2017 às 17:33, Adam Kemp < >>>> adam.kemp@apple.com >>>> <mailto:adam.kemp@apple.com>> escreveu:

                How would these anonymous types get composed? If I
wanted to
                implement a function that takes a collection of futures
and wait
                on it, how would I do that? That is, how would I
implement the
                equivalent of C#’s Task.WhenAll and Task.WhenAny
methods?

                More generally, how do you pass one of these typeless
futures to
                some other function so that we can do the waiting there?

                On Aug 28, 2017, at 1:23 PM, Wallacy < >>>>> wallacyf@gmail.com >>>>> <mailto:wallacyf@gmail.com>> wrote:

                And that's why I (and others) are suggesting:

                func processImageData1a() async -> Image {
                  let dataResource = async
loadWebResource("dataprofile.txt") //
                No future type here... Just another way to call
dispatch_async
                under the hood.
                  let imageResource = async
loadWebResource("imagedata.dat")
                  // ... other stuff can go here to cover load
latency...
                  let imageTmp = await decodeImage(dataResource,
                imageResource) // Compiles force await call here...
                  let imageResult = await
dewarpAndCleanupImage(imageTmp)
                  return imageResult
                }

                And now we gain all advantages of async/await again
without to
                handle with one more type.

                Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via
swift-evolution
                <swift-evolution@swift.org <mailto:
swift-evolution@swift.org>>

                escreveu:

                    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.c
om/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 >>>>>> <florent@flovilmart.com <mailto: >>>>>> florent@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.kemp@apple.com >>>>>> <mailto:adam.kemp@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.lovatt@gmail.com <mailto: >>>>>>> howard.lovatt@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=
awaitloadWebResource("dataprofile.txt")
                       let imageResource=
awaitloadWebResource("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.kemp@apple.com >>>>>>>> <mailto:adam.kemp@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 >>>>>>>>> <florent@flovilmart.com >>>>>>>>> <mailto:florent@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 >>>>>>>>>>> <jgroff@apple.com <mailto: >>>>>>>>>>> jgroff@apple.com>> wrote:

                                On Aug 25, 2017, at 12:34 AM, >>>>>>>>>>>> Howard >>>>>>>>>>>> Lovatt <howard.lovatt@gmail.com >>>>>>>>>>>> <mailto:howard.lovatt@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/mailma
n/listinfo/swift-evolution

                        --
                        -- Howard.
                        ______________________________
_________________
                        swift-evolution mailing list
                        swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        https://lists.swift.org/mailma
n/listinfo/swift-evolution

                    _______________________________________________
                    swift-evolution mailing list
                    swift-evolution@swift.org <mailto:
swift-evolution@swift.org>
                    https://lists.swift.org/mailma
n/listinfo/swift-evolution

            _______________________________________________
            swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

@David,

The signatures would be:

func processImage(_ image: Future<Image>) -> Future<Image>

func translate(_ text: Future<String>) -> Future<Image>

Inside `processImage` and `translate` you would `get` the values at the
point were needed so that downloadImage and downloadText run in parallel
(which is highly desirable).

  -- Howard.

···

On 30 August 2017 at 07:21, David Hart <david@hartbit.com> wrote:

I don’t think the examples are 100% equivalent. In your version with the
Future library, *preprocessImage* and *translate* need to accept futures
as argument, correct? That’s more restrictive than in my example code where
async/await specifically provide sugar over *then*. Plus I don’t
understand why you mention that the Future version handles errors when
async/await also plays very nicely with errors.

On 29 Aug 2017, at 10:22, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

Using the `Future` library based on GCD that I have previously posted your
example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallellet text = translate(downloadText())render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the
`Future` version handles errors.

So what advantage does async/await have over a `Future` library we can
write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution < > swift-evolution@swift.org> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution < >> swift-evolution@swift.org> wrote:

I know what the proposal said. I’m making a case that there is value in
doing it differently.

The composability of futures is valuable. Mixing and matching
async/await with futures is also valuable. The queue-returning behavior
that you can get from futures is also valuable, and building async/await on
top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the
queue-return behavior of futures if futures are built on top of async/await
instead off the other way around?

We could, but the syntax is much worse. Contrast:

*async/await built on top of Futures*

let image = preprocessImage(downloadImage())let text = translate(downloadText())
await render(image: image, text: text)

*Futures built on top of async/await*

let image = Future(downloadImage).then({ preprocessImage($0) })let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe

other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to
acknowledge that it comes with a downside as well. The problem with doing a
minimal implementation is that you can be stuck with the consequences for a
long time. I want to make sure that we’re not stuck with the consequences
of a minimal implementation that doesn’t adequately address the problems
that async/await should be addressing. I’d hate for Swift to get an
async/await that is so weak that it has to be augmented by tedious
boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support
that is completely concurrency runtime-agnostic. This proposal does not
include a new runtime model (like "actors") - it works just as well with
GCD as with pthreads or another API. Furthermore, unlike designs in other
languages, it is independent of specific coordination mechanisms, such as
futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other
coordination abstractions. There are many rational designs for futures, and
a lot of experience working with them. On the other hand, there are also
completely different coordination primitives that can be used with this
coroutine design, and incorporating them into this proposal only makes it
larger."

and

We focus on task-based concurrency abstractions commonly encountered in
client and server applications, particularly those that are highly event
driven (e.g. responding to UI events or requests from clients). This does
not attempt to be a comprehensive survey of all possible options, nor does
it attempt to solve all possible problems in the space of concurrency.
Instead, it outlines a single coherent design thread that can be built over
the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many
possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic
async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ?
dispatch_async also does not return nothing to do what you are intentend do
do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete"
concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the
ground free to make more complex implementation like Futures in another
round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But
doesn't matter now! Now we only need to is some kind of type which need to
be unwrapped using await before use. Maybe this intermediary/virtual type
can be a real thing and gain some abilities at some point! Maybe a full
Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com> >>> escreveu:

How would these anonymous types get composed? If I wanted to implement
a function that takes a collection of futures and wait on it, how would I
do that? That is, how would I implement the equivalent of C#’s Task.WhenAll
and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some
other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No
future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")

  // ... other stuff can go here to cover load latency...

  let imageTmp = await decodeImage(dataResource, imageResource) //
Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle
with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution < >>>> swift-evolution@swift.org> escreveu:

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:
await anything; - .NET Parallel Programming).
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 <florent@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.kemp@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.lovatt@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.kemp@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> 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 < >>>>>> florent@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>, 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> 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 <jgroff@apple.com> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt < >>>>>>>> howard.lovatt@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
https://lists.swift.org/mailman/listinfo/swift-evolution

--

-- Howard.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Oops I missed some awaits out in the async/await version I just posted.
Correct async/await version for parallel execution is:

func updateImage() async {

let image: Image

async do { // Runs in parallel (async)

image = try async preprocessImage(await downloadImage()) // Need to wait
for download

} catch {

image = defaultImage

}

let text: String

async do { // Runs in parallel (async)

text = try async translate(await downloadText()) // Need to wait for
download

} catch {

text = defaultText

}
// This line is complicated! We want render not to block (async), but have
to await for image and text.
// Render does not throw because it always has valid input.
// If async were allowed to prevent blocking then await could not

async render(image: await image, text: await text)

}

PS I think it was Wallacy not Vladimir who suggested the parallel version
using async - another mistake in the previous post - sorry.

  -- Howard.

···

On 30 August 2017 at 02:02, Wallacy <wallacyf@gmail.com> wrote:

In this example i think we lose clarity, just looking for the code we cant
know if this two line will run on parallel or not!
Also, image.get blocks the thread, in this case we need the await anyway!
And `async` can throws too... So the error handler can be pretty similar.

let image = async preprocessImage(downloadImage()) // These first two lines run in parallel and I can "see" the async keyword.let text = async translate(downloadText())await render(image: image ?? defaultImage, text: text ?? defaultText) // No blocking!

Like i said before! Today's, the proposal only lack two things over the
`Future`....
Parallel computing: Can be implemented by a third party library or a
personal one, but i don't think this is a good approach to the first
version.
Coordination: This we can wait! And why? Because coordination, can be made
in different ways, maybe is more suitable to a standard library
class/function, not a language level resource.

Also, coordination cant be applied to all variants of the runtimes in the
same way! async/await as language level works just as well with GCD as
with pthreads or another API. And coordination is a compromise that we can
make after that one.

Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> escreveu:

@David,

Using the `Future` library based on GCD that I have previously posted
your example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallellet text = translate(downloadText())render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the
`Future` version handles errors.

So what advantage does async/await have over a `Future` library we can
write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution < >> swift-evolution@swift.org> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution < >>> swift-evolution@swift.org> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution < >>> swift-evolution@swift.org> wrote:

I know what the proposal said. I’m making a case that there is value in
doing it differently.

The composability of futures is valuable. Mixing and matching
async/await with futures is also valuable. The queue-returning behavior
that you can get from futures is also valuable, and building async/await on
top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the
queue-return behavior of futures if futures are built on top of async/await
instead off the other way around?

We could, but the syntax is much worse. Contrast:

*async/await built on top of Futures*

let image = preprocessImage(downloadImage())let text = translate(downloadText())
await render(image: image, text: text)

*Futures built on top of async/await*

let image = Future(downloadImage).then({ preprocessImage($0) })let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe

other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to
acknowledge that it comes with a downside as well. The problem with doing a
minimal implementation is that you can be stuck with the consequences for a
long time. I want to make sure that we’re not stuck with the consequences
of a minimal implementation that doesn’t adequately address the problems
that async/await should be addressing. I’d hate for Swift to get an
async/await that is so weak that it has to be augmented by tedious
boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support
that is completely concurrency runtime-agnostic. This proposal does not
include a new runtime model (like "actors") - it works just as well with
GCD as with pthreads or another API. Furthermore, unlike designs in other
languages, it is independent of specific coordination mechanisms, such as
futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other
coordination abstractions. There are many rational designs for futures, and
a lot of experience working with them. On the other hand, there are also
completely different coordination primitives that can be used with this
coroutine design, and incorporating them into this proposal only makes it
larger."

and

We focus on task-based concurrency abstractions commonly encountered in
client and server applications, particularly those that are highly event
driven (e.g. responding to UI events or requests from clients). This does
not attempt to be a comprehensive survey of all possible options, nor does
it attempt to solve all possible problems in the space of concurrency.
Instead, it outlines a single coherent design thread that can be built over
the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many
possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic
async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ?
dispatch_async also does not return nothing to do what you are intentend do
do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete"
concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the
ground free to make more complex implementation like Futures in another
round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But
doesn't matter now! Now we only need to is some kind of type which need to
be unwrapped using await before use. Maybe this intermediary/virtual type
can be a real thing and gain some abilities at some point! Maybe a full
Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com> >>>> escreveu:

How would these anonymous types get composed? If I wanted to implement
a function that takes a collection of futures and wait on it, how would I
do that? That is, how would I implement the equivalent of C#’s Task.WhenAll
and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some
other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No
future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")

  // ... other stuff can go here to cover load latency...

  let imageTmp = await decodeImage(dataResource, imageResource) //
Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle
with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution < >>>>> swift-evolution@swift.org> escreveu:

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:
await anything; - .NET Parallel Programming).
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 <florent@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.kemp@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.lovatt@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.kemp@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> 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 < >>>>>>> florent@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>, 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> 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 <jgroff@apple.com> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt < >>>>>>>>> howard.lovatt@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
https://lists.swift.org/mailman/listinfo/swift-evolution

--

-- Howard.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I understand. But it’s quite problematic to have to write all Future returning functions with Future inputs just to be able to support parallel computations. It’s not how futures are using in C# and JavaScript.

···

On 30 Aug 2017, at 03:02, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

The signatures would be:

func processImage(_ image: Future<Image>) -> Future<Image>
func translate(_ text: Future<String>) -> Future<Image>

Inside `processImage` and `translate` you would `get` the values at the point were needed so that downloadImage and downloadText run in parallel (which is highly desirable).

  -- Howard.

On 30 August 2017 at 07:21, David Hart <david@hartbit.com> wrote:
I don’t think the examples are 100% equivalent. In your version with the Future library, preprocessImage and translate need to accept futures as argument, correct? That’s more restrictive than in my example code where async/await specifically provide sugar over then. Plus I don’t understand why you mention that the Future version handles errors when async/await also plays very nicely with errors.

On 29 Aug 2017, at 10:22, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

Using the `Future` library based on GCD that I have previously posted your example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallel
let text = translate(downloadText())
render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the `Future` version handles errors.

So what advantage does async/await have over a `Future` library we can write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution <swift-evolution@swift.org> wrote:
I know what the proposal said. I’m making a case that there is value in doing it differently.

The composability of futures is valuable. Mixing and matching async/await with futures is also valuable. The queue-returning behavior that you can get from futures is also valuable, and building async/await on top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the queue-return behavior of futures if futures are built on top of async/await instead off the other way around?

We could, but the syntax is much worse. Contrast:

async/await built on top of Futures

let image = preprocessImage(downloadImage())
let text = translate(downloadText())
await render(image: image, text: text)

Futures built on top of async/await

let image = Future(downloadImage).then({ preprocessImage($0) })
let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to acknowledge that it comes with a downside as well. The problem with doing a minimal implementation is that you can be stuck with the consequences for a long time. I want to make sure that we’re not stuck with the consequences of a minimal implementation that doesn’t adequately address the problems that async/await should be addressing. I’d hate for Swift to get an async/await that is so weak that it has to be augmented by tedious boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support that is completely concurrency runtime-agnostic. This proposal does not include a new runtime model (like "actors") - it works just as well with GCD as with pthreads or another API. Furthermore, unlike designs in other languages, it is independent of specific coordination mechanisms, such as futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other coordination abstractions. There are many rational designs for futures, and a lot of experience working with them. On the other hand, there are also completely different coordination primitives that can be used with this coroutine design, and incorporating them into this proposal only makes it larger."

and

We focus on task-based concurrency abstractions commonly encountered in client and server applications, particularly those that are highly event driven (e.g. responding to UI events or requests from clients). This does not attempt to be a comprehensive survey of all possible options, nor does it attempt to solve all possible problems in the space of concurrency. Instead, it outlines a single coherent design thread that can be built over the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ? dispatch_async also does not return nothing to do what you are intentend do do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete" concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the ground free to make more complex implementation like Futures in another round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But doesn't matter now! Now we only need to is some kind of type which need to be unwrapped using await before use. Maybe this intermediary/virtual type can be a real thing and gain some abilities at some point! Maybe a full Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com> escreveu:
How would these anonymous types get composed? If I wanted to implement a function that takes a collection of futures and wait on it, how would I do that? That is, how would I implement the equivalent of C#’s Task.WhenAll and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")
  
  // ... other stuff can go here to cover load latency...
  
  let imageTmp = await decodeImage(dataResource, imageResource) // Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution <swift-evolution@swift.org> escreveu:
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: await anything; - .NET Parallel Programming). 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 <florent@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.kemp@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.lovatt@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.kemp@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> 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 <florent@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>, 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> 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 <jgroff@apple.com> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt <howard.lovatt@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
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-- Howard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

@Vladimir,

Default values are a problem for await/async when combined with parallel running because await returns a value and not an optional (unlike future's get). Below is a more realistic code for parallel running and a default value using async/await:

Thank you for the reply. Seems I'm missing something important, but

async render(image: await image, text: await text)

, as I understand currently, should NOT block the execution, execution will back here when image&text are 'ready', while

render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

should block on .get(). No? This is why I asked if we need some 'sync' modifier like

sync preprocessImage(someImage)
, if we need to call func declared as async synchronously.

Vladimir.

···

On 30.08.2017 3:43, Howard Lovatt wrote:

    func updateImage() async {

        let image: Image

        async do { // Runs in parallel (async)

            image = try async preprocessImage(downloadImage())

        } catch {

            image = defaultImage

        }

        let text: String

        async do { // Runs in parallel (async)

            text = try async translate(downloadText())

        } catch {

            text = defaultText

        }
        // This line is complicated! We want render not to block (async), but have to
        await for image and text.
        // Render does not throw because it always has valid input.
        // If async were allowed to prevent blocking then await could not

        async render(image: await image, text: await text)

    }

Which I don't think reads as well as the Future version:

    func updateImage() -> Future<Void> {

        return AsynchronousFuture { _ -> Void in

            let image = preprocessImage(downloadImage()) // Parallel, Futures are
            queued on creation

            let text = translate(downloadText()) // Parallel, Futures are queued on
            creation

            // Does not block (Futures are queued on creation), but has to wait for
            its inputs (get).

            render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

        }

    }

In addition the async/await version does not have timeout; unlike the Future version.

Suppose that downloadImage doesn't fail, it just takes forever to download the image. The Future version will timeout automatically and the default image will be used. With async/await the code for downloadImage and downloadText will have to start timers and throw if the timers timeout. Nothing to do in the Future version, it handles timeout for you.

Neither or the above versions have cancel or control over the queue they execute on, but both would be much easier to add to the Future version, like timeout is much easier to add, since Futures support cancel and queue control directly.

   -- Howard.

On 30 August 2017 at 02:45, Vladimir.S via swift-evolution <swift-evolution@swift.org > <mailto:swift-evolution@swift.org>> wrote:

    On 29.08.2017 19:02, Wallacy via swift-evolution wrote:

        In this example i think we lose clarity, just looking for the code we cant
        know if this two line will run on parallel or not!
        Also, image.get blocks the thread, in this case we need the await anyway! And
        `async` can throws too... So the error handler can be pretty similar.

        let image= asyncpreprocessImage(downloadImage()) // These first two lines
        run in parallel and I can "see" the async keyword.
        let text= asynctranslate(downloadText())
        await render(image: image ?? defaultImage,text: text ?? defaultText) // No
        blocking!

    FWIW: I'm following the whole discussion from the start, and do support the
    opinion that async/await is much clear solution that proposed Futures, especially
    for beginners.
    We need a low-level building blocks which can be used to implement
    Futures/Promises in libraries.
    Also I really like the idea of 'async' on the caller side to have code running in
    parallel.

    The 'async' version of func declaration is clearly saying what type it *want* to
    return, and 'async' modifier just saying *how* it will/can return that
    type('Image' in examples). So on both sides, on declaration and on caller side,
    we are clear what types we are working with.
    Future<Type> - is mixing of what is returning and how this will be returned. Code
    is saying that we preprocessesImage, but actually we have Future<Image> type, no
    'markers' of asynchronous code.

    Also, I wonder(if I missed that in proposal/discussion, please let me know), if I
    have async function like

    func foo() async -> Type {}

    , may I want to call it synchronously? If so, what would be a solution here? I
    can think about something like 'sync' modifier on caller side:
    let x = sync foo() // calling asynchronous function synchronously

    I believe that is what Future.get is doing, no?
    let future = ...
    future.get() // blocks the execution, waits for the result.

    Probably it is reasonable to allow just call foo() to get blocking result, just
    like any other 'simple' blocking funcs that we call, but this can lead to
    unexpected behavior as user can expect async execution.

    With Futures, it seems like we can't "just" call such function and need to call
    .get() later:
    let future = someFuncReturnsFuture() // already returns Future<Type> type

    Vladimir.

        Like i said before! Today's, the proposal only lack two things over the
        `Future`....
        Parallel computing: Can be implemented by a third party library or a personal
        one, but i don't think this is a good approach to the first version.
        Coordination: This we can wait! And why? Because coordination, can be made in
        different ways, maybe is more suitable to a standard library class/function,
        not a language level resource.

        Also, coordination cant be applied to all variants of the runtimes in the
        same way! async/await as language level works just as well with GCD as with
        pthreads or another API. And coordination is a compromise that we can make
        after that one.

        Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> escreveu:

             @David,

             Using the `Future` library based on GCD that I have previously posted your
             example would be:

             let image= preprocessImage(downloadImage()) // These first two lines
        run in parallel
             let text= translate(downloadText())
             render(image: image.get ?? defaultImage,text: text.get ?? defaultText)

             The main difference, and I would argue an improvement, is that the `Future`
             version handles errors.

             So what advantage does async/await have over a `Future` library we can
        write today?

                -- Howard.

             On 29 August 2017 at 15:28, David Hart via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:

                     On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:

                     On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org> > <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:

                         I know what the proposal said. I’m making a case that there
            is value in
                         doing it differently.

                         The composability of futures is valuable. Mixing and matching
                         async/await with futures is also valuable. The
            queue-returning behavior
                         that you can get from futures is also valuable, and building
                         async/await on top of futures means async/await can get that
            for free.

                     Why couldn't you mix and match async/await and futures and get the
                     queue-return behavior of futures if futures are built on top of
            async/await
                     instead off the other way around?

                 We could, but the syntax is much worse. Contrast:

                 *async/await built on top of Futures*
                 *

                 let image= preprocessImage(downloadImage())
                 let text= translate(downloadText())
                 awaitrender(image: image,text: text)

                 *Futures built on top of async/await*
                 *

                 let image= Future(downloadImage).then({preprocessImage($0) })
                 let text= Future(downloadText).then({translate($0) })
                 awaitrender(image: image.get(),text: text.get())

                         Maybe you don’t value those things, which is fine. But I do,
            and maybe
                         other people do too. That’s why we’re having a discussion
            about it.

                         It can also be valuable having a minimal implementation, but
            we have to
                         acknowledge that it comes with a downside as well. The
            problem with
                         doing a minimal implementation is that you can be stuck with the
                         consequences for a long time. I want to make sure that we’re
            not stuck
                         with the consequences of a minimal implementation that doesn’t
                         adequately address the problems that async/await should be
            addressing.
                         I’d hate for Swift to get an async/await that is so weak
            that it has to
                         be augmented by tedious boilerplate code before it’s useful.

                             On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com > <mailto:wallacyf@gmail.com> > <mailto:wallacyf@gmail.com <mailto:wallacyf@gmail.com>>> > wrote:

                             We don't need to this now!

                             Again: (Using proposal words)

                             "It is important to understand that this is proposing
                compiler support
                             that is completely concurrency runtime-agnostic. This
                proposal does
                             not include a new runtime model (like "actors") - it
                works just as
                             well with GCD as with pthreads or another API.
                Furthermore, unlike
                             designs in other languages, it is independent of
                specific coordination
                             mechanisms, such as futures or channels, allowing these
                to be built as
                             library feature"

                             and

                             "This proposal does not formally propose a |Future|
                type, or any other
                             coordination abstractions. There are many rational
                designs for
                             futures, and a lot of experience working with them. On
                the other hand,
                             there are also completely different coordination
                primitives that can
                             be used with this coroutine design, and incorporating
                them into this
                             proposal only makes it larger."

                             and

                             We focus on task-based concurrency abstractions commonly
                encountered
                             in client and server applications, particularly those
                that are highly
                             event driven (e.g. responding to UI events or requests
                from clients).
                             This does not attempt to be a comprehensive survey of
                all possible
                             options, nor does it attempt to solve all possible
                problems in the
                             space of concurrency. Instead, it outlines a single
                coherent design
                             thread that can be built over the span of years to
                incrementally drive
                             Swift to further greatness.

                             and

                             This proposal has been kept intentionally minimal, but
                there are many
                             possible ways to expand this in the future.

                             ....

                             The point is: No Future type is indeed proposed yet!

                             The proposal try to include de "minimum" required to
                implement a basic
                             async/await to solve the problem created by the GCD!
                (Pyramid of doom)

                             The question is: How do you do the same using
                dispatch_async ?
                             dispatch_async also does not return nothing to do what
                you are
                             intentend do do!

                             Algo, by Swift 5 manifesto, there's no compromise to
                make a "complete"
                             concurrency model by this time!

                             My intention is only make parity to dispatch_async, but
                also make the
                             ground free to make more complex implementation like
                Futures in
                             another round on top of this one.

                             This 'async T' can be a real type in the future? Maybe
                will... But
                             doesn't matter now! Now we only need to is some kind of
                type which
                             need to be unwrapped using await before use. Maybe this
                             intermediary/virtual type can be a real thing and gain
                some abilities
                             at some point! Maybe a full Future type, why not?

                             Em seg, 28 de ago de 2017 às 17:33, Adam Kemp > <adam.kemp@apple.com <mailto:adam.kemp@apple.com> > <mailto:adam.kemp@apple.com > <mailto:adam.kemp@apple.com>>> escreveu:

                                 How would these anonymous types get composed? If I
                wanted to
                                 implement a function that takes a collection of
                futures and wait
                                 on it, how would I do that? That is, how would I
                implement the
                                 equivalent of C#’s Task.WhenAll and Task.WhenAny
                methods?

                                 More generally, how do you pass one of these
                typeless futures to
                                 some other function so that we can do the waiting there?

                                     On Aug 28, 2017, at 1:23 PM, Wallacy > <wallacyf@gmail.com <mailto:wallacyf@gmail.com> > <mailto:wallacyf@gmail.com > <mailto:wallacyf@gmail.com>>> wrote:

                                     And that's why I (and others) are suggesting:

                                     func processImageData1a() async -> Image {
                                       let dataResource = async
                    loadWebResource("dataprofile.txt") //
                                     No future type here... Just another way to call
                    dispatch_async
                                     under the hood.
                                       let imageResource = async
                    loadWebResource("imagedata.dat")
                                       // ... other stuff can go here to cover load
                    latency...
                                       let imageTmp = await decodeImage(dataResource,
                                     imageResource) // Compiles force await call here...
                                       let imageResult = await
                    dewarpAndCleanupImage(imageTmp)
                                       return imageResult
                                     }

                                     And now we gain all advantages of async/await
                    again without to
                                     handle with one more type.

                                     Em seg, 28 de ago de 2017 às 17:07, Adam Kemp
                    via swift-evolution
                                     <swift-evolution@swift.org
                    <mailto:swift-evolution@swift.org>
                    <mailto:swift-evolution@swift.org
                    <mailto:swift-evolution@swift.org>>>

                                     escreveu:

                                         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:
                    await anything; - .NET Parallel Programming
                    <https://blogs.msdn.microsoft.com/pfxteam/2011/01/13/await-anything/&gt;\).
                                         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 > <florent@flovilmart.com > <mailto:florent@flovilmart.com> > <mailto:florent@flovilmart.com > <mailto:florent@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.kemp@apple.com <mailto:adam.kemp@apple.com> > <mailto:adam.kemp@apple.com > <mailto:adam.kemp@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.lovatt@gmail.com
                            <mailto:howard.lovatt@gmail.com>
                            <mailto:howard.lovatt@gmail.com
                            <mailto:howard.lovatt@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= awaitloadWebResource("dataprofile.txt")
                                                        let imageResource= awaitloadWebResource("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.kemp@apple.com <mailto:adam.kemp@apple.com> > <mailto:adam.kemp@apple.com > <mailto:adam.kemp@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>
                                                                                        <mailto: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
                                                             <florent@flovilmart.com
                                    <mailto:florent@flovilmart.com>
                                                                                                <mailto:florent@flovilmart.com
                                    <mailto:florent@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>
                                                                                                    <mailto: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>
                                                                                                            <mailto: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
                                                                                                                    <jgroff@apple.com
                                            <mailto:jgroff@apple.com>
                                            <mailto:jgroff@apple.com
                                            <mailto:jgroff@apple.com>>> wrote:

                                                                                 On
                                                Aug 25, 2017, at 12:34 AM, Howard
                                                                                                                                Lovatt <howard.lovatt@gmail.com
                                                <mailto:howard.lovatt@gmail.com>
                                                                                                                                <mailto:howard.lovatt@gmail.com
                                                <mailto:howard.lovatt@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>
                                                                                                                    <mailto: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&gt;

                                                             --
                                                             -- Howard.
                                                                                                _______________________________________________
                                                             swift-evolution mailing list
                                    swift-evolution@swift.org
                                    <mailto:swift-evolution@swift.org>
                                                                                                <mailto: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&gt;

                                         _______________________________________________
                                         swift-evolution mailing list
                    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
                    <mailto: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&gt;

                         _______________________________________________
                         swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            <mailto: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&gt;

                     _______________________________________________
                     swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org>
            <mailto: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&gt;

                 _______________________________________________
                 swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        <mailto: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&gt;

             _______________________________________________
             swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        <mailto: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&gt;

        _______________________________________________
        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&gt;

    _______________________________________________
    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&gt;

@Howard,

First, you comparison is unfair! You cannot compare on aproach using throws
error handle vs another wich ignore the error and get a optional back. The
correct code is:

func updateImage() async {

let image: try? async preprocessImage(downloadImage()) ?? defaultImage

let text = try? async translate(downloadText()) ?? defaultText

await render(image: image, text: text)

}

Also, you fail on justify why Future need to return a optional! You are
only making Futures looks worse! You are ignoring all non failable
possibilities! Also, doesn't make any sense to make `render` async because
await will not block the thread anyway, and the call side of the
updateImage will call await in this function at some point too!

(Int) -> Int // #1: Normal function (Int) throws ->
Int // #2: Throwing function (Int) async -> Int //
#3: Asynchronous function (Int) async throws -> Int // #4:
Asynchronous function, can also throw.

This is pretty easy and make much more sense!

Also you are thinking too hard to explain why Futures is great! Ok! We know
that! Future could be the next step!

The question is not if Future is good or not! The question is: Whats the
benefice of use Future on top of async/await, instead the oposite! And
nothing that you show here prove that!

Also, this is the Fist step, if, only if we implement Future first, we will
not get cancelable returns, timeouts, etc... And the big question: How
implement a Future class do interop with CGD in a "Swift way"

How do you create a mask to some Cocoa API witch return:

func processImageData(completionHandler: (result: Image) -> Void) { ... }

Using this?

func processImageData() -> Future<Image> { ... }

This doesn't make any sense! Create another object every time? Now all
calls need to be intercept.... And a lot of other problems!
Because Future.get() (like you said) will return a optional value, and we
also need handle with that on our code.

Translate to this:

func processImageData() async -> Image { ... }

It's easy to understand, easy to compile only generate the "original"
signature, do not evolve any specific mechanism... and... ok. Just look at
the proposal, its all there! We need something easy to be translated to a
GCD call now, and maybe pthreads or others API in the future!

You are trying to solve one problem, but the role proposal is about another
problem!

Everyone can understand the Future type can do more thinks! It's already on
proposal this notion! And we are trying to discuse what is the ground layer
to implement Task/Futures and other things in a good way! Also, to solve
one problem which we have now!

A complete concurrence model will arrive at the time!

···

Em ter, 29 de ago de 2017 às 21:43, Howard Lovatt <howard.lovatt@gmail.com> escreveu:

@Vladimir,

Default values are a problem for await/async when combined with parallel
running because await returns a value and not an optional (unlike future's
get). Below is a more realistic code for parallel running and a default
value using async/await:

func updateImage() async {

let image: Image

async do { // Runs in parallel (async)

image = try async preprocessImage(downloadImage())

} catch {

image = defaultImage

}

let text: String

async do { // Runs in parallel (async)

text = try async translate(downloadText())

} catch {

text = defaultText

}

// This line is complicated! We want render not to block (async), but have
to await for image and text.
// Render does not throw because it always has valid input.
// If async were allowed to prevent blocking then await could not

async render(image: await image, text: await text)

}

Which I don't think reads as well as the Future version:

func updateImage() -> Future<Void> {

return AsynchronousFuture { _ -> Void in

let image = preprocessImage(downloadImage()) // Parallel, Futures are
queued on creation

let text = translate(downloadText()) // Parallel, Futures are queued on
creation

// Does not block (Futures are queued on creation), but has to wait for
its inputs (get).

render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

}

}

In addition the async/await version does not have timeout; unlike the
Future version.

Suppose that downloadImage doesn't fail, it just takes forever to
download the image. The Future version will timeout automatically and the
default image will be used. With async/await the code for downloadImage and
downloadText will have to start timers and throw if the timers timeout.
Nothing to do in the Future version, it handles timeout for you.

Neither or the above versions have cancel or control over the queue they
execute on, but both would be much easier to add to the Future version,
like timeout is much easier to add, since Futures support cancel and queue
control directly.

  -- Howard.

On 30 August 2017 at 02:45, Vladimir.S via swift-evolution < > swift-evolution@swift.org> wrote:

On 29.08.2017 19:02, Wallacy via swift-evolution wrote:

In this example i think we lose clarity, just looking for the code we
cant know if this two line will run on parallel or not!
Also, image.get blocks the thread, in this case we need the await
anyway! And `async` can throws too... So the error handler can be pretty
similar.

let image= asyncpreprocessImage(downloadImage()) // These first two
lines run in parallel and I can "see" the async keyword.
let text= asynctranslate(downloadText())
await render(image: image ?? defaultImage,text: text ?? defaultText) //
No blocking!

FWIW: I'm following the whole discussion from the start, and do support
the opinion that async/await is much clear solution that proposed Futures,
especially for beginners.
We need a low-level building blocks which can be used to implement
Futures/Promises in libraries.
Also I really like the idea of 'async' on the caller side to have code
running in parallel.

The 'async' version of func declaration is clearly saying what type it
*want* to return, and 'async' modifier just saying *how* it will/can return
that type('Image' in examples). So on both sides, on declaration and on
caller side, we are clear what types we are working with.
Future<Type> - is mixing of what is returning and how this will be
returned. Code is saying that we preprocessesImage, but actually we have
Future<Image> type, no 'markers' of asynchronous code.

Also, I wonder(if I missed that in proposal/discussion, please let me
know), if I have async function like

func foo() async -> Type {}

, may I want to call it synchronously? If so, what would be a solution
here? I can think about something like 'sync' modifier on caller side:
let x = sync foo() // calling asynchronous function synchronously

I believe that is what Future.get is doing, no?
let future = ...
future.get() // blocks the execution, waits for the result.

Probably it is reasonable to allow just call foo() to get blocking
result, just like any other 'simple' blocking funcs that we call, but this
can lead to unexpected behavior as user can expect async execution.

With Futures, it seems like we can't "just" call such function and need
to call .get() later:
let future = someFuncReturnsFuture() // already returns Future<Type> type

Vladimir.

Like i said before! Today's, the proposal only lack two things over the
`Future`....
Parallel computing: Can be implemented by a third party library or a
personal one, but i don't think this is a good approach to the first
version.
Coordination: This we can wait! And why? Because coordination, can be
made in different ways, maybe is more suitable to a standard library
class/function, not a language level resource.

Also, coordination cant be applied to all variants of the runtimes in
the same way! async/await as language level works just as well with GCD as
with pthreads or another API. And coordination is a compromise that we can
make after that one.

Em ter, 29 de ago de 2017 às 05:23, Howard Lovatt via swift-evolution < >>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:

    @David,

    Using the `Future` library based on GCD that I have previously
posted your
    example would be:

    let image= preprocessImage(downloadImage()) // These first two
lines run in parallel
    let text= translate(downloadText())
    render(image: image.get ?? defaultImage,text: text.get ??
defaultText)

    The main difference, and I would argue an improvement, is that the
`Future`
    version handles errors.

    So what advantage does async/await have over a `Future` library we
can write today?

       -- Howard.

    On 29 August 2017 at 15:28, David Hart via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>> wrote:

        On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>>> wrote:

        On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>>> wrote:

            I know what the proposal said. I’m making a case that there
is value in
            doing it differently.

            The composability of futures is valuable. Mixing and
matching
            async/await with futures is also valuable. The
queue-returning behavior
            that you can get from futures is also valuable, and building
            async/await on top of futures means async/await can get
that for free.

        Why couldn't you mix and match async/await and futures and get
the
        queue-return behavior of futures if futures are built on top of
async/await
        instead off the other way around?

        We could, but the syntax is much worse. Contrast:

        *async/await built on top of Futures*
        *
        *

        let image= preprocessImage(downloadImage())
        let text= translate(downloadText())
        awaitrender(image: image,text: text)

        *Futures built on top of async/await*
        *
        *

        let image= Future(downloadImage).then({preprocessImage($0) })
        let text= Future(downloadText).then({translate($0) })
        awaitrender(image: image.get(),text: text.get())

            Maybe you don’t value those things, which is fine. But I do,

and maybe
            other people do too. That’s why we’re having a discussion
about it.

            It can also be valuable having a minimal implementation,
but we have to
            acknowledge that it comes with a downside as well. The
problem with
            doing a minimal implementation is that you can be stuck
with the
            consequences for a long time. I want to make sure that
we’re not stuck
            with the consequences of a minimal implementation that
doesn’t
            adequately address the problems that async/await should be
addressing.
            I’d hate for Swift to get an async/await that is so weak
that it has to
            be augmented by tedious boilerplate code before it’s useful.

            On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com >>>>> <mailto:wallacyf@gmail.com>> wrote:

            We don't need to this now!

            Again: (Using proposal words)

            "It is important to understand that this is proposing
compiler support
            that is completely concurrency runtime-agnostic. This
proposal does
            not include a new runtime model (like "actors") - it works
just as
            well with GCD as with pthreads or another API.
Furthermore, unlike
            designs in other languages, it is independent of specific
coordination
            mechanisms, such as futures or channels, allowing these to
be built as
            library feature"

            and

            "This proposal does not formally propose a |Future| type,
or any other
            coordination abstractions. There are many rational designs
for
            futures, and a lot of experience working with them. On the
other hand,
            there are also completely different coordination
primitives that can
            be used with this coroutine design, and incorporating them
into this
            proposal only makes it larger."

            and

            We focus on task-based concurrency abstractions commonly
encountered
            in client and server applications, particularly those that
are highly
            event driven (e.g. responding to UI events or requests
from clients).
            This does not attempt to be a comprehensive survey of all
possible
            options, nor does it attempt to solve all possible
problems in the
            space of concurrency. Instead, it outlines a single
coherent design
            thread that can be built over the span of years to
incrementally drive
            Swift to further greatness.

            and

            This proposal has been kept intentionally minimal, but
there are many
            possible ways to expand this in the future.

            ....

            The point is: No Future type is indeed proposed yet!

            The proposal try to include de "minimum" required to
implement a basic
            async/await to solve the problem created by the GCD!
(Pyramid of doom)

            The question is: How do you do the same using
dispatch_async ?
            dispatch_async also does not return nothing to do what you
are
            intentend do do!

            Algo, by Swift 5 manifesto, there's no compromise to make
a "complete"
            concurrency model by this time!

            My intention is only make parity to dispatch_async, but
also make the
            ground free to make more complex implementation like
Futures in
            another round on top of this one.

            This 'async T' can be a real type in the future? Maybe
will... But
            doesn't matter now! Now we only need to is some kind of
type which
            need to be unwrapped using await before use. Maybe this
            intermediary/virtual type can be a real thing and gain
some abilities
            at some point! Maybe a full Future type, why not?

            Em seg, 28 de ago de 2017 às 17:33, Adam Kemp < >>>>> adam.kemp@apple.com >>>>> <mailto:adam.kemp@apple.com>> escreveu:

                How would these anonymous types get composed? If I
wanted to
                implement a function that takes a collection of
futures and wait
                on it, how would I do that? That is, how would I
implement the
                equivalent of C#’s Task.WhenAll and Task.WhenAny
methods?

                More generally, how do you pass one of these typeless
futures to
                some other function so that we can do the waiting
there?

                On Aug 28, 2017, at 1:23 PM, Wallacy < >>>>>> wallacyf@gmail.com >>>>>> <mailto:wallacyf@gmail.com>> wrote:

                And that's why I (and others) are suggesting:

                func processImageData1a() async -> Image {
                  let dataResource = async
loadWebResource("dataprofile.txt") //
                No future type here... Just another way to call
dispatch_async
                under the hood.
                  let imageResource = async
loadWebResource("imagedata.dat")
                  // ... other stuff can go here to cover load
latency...
                  let imageTmp = await decodeImage(dataResource,
                imageResource) // Compiles force await call here...
                  let imageResult = await
dewarpAndCleanupImage(imageTmp)
                  return imageResult
                }

                And now we gain all advantages of async/await again
without to
                handle with one more type.

                Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via
swift-evolution
                <swift-evolution@swift.org <mailto:
swift-evolution@swift.org>>

                escreveu:

                    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:

await anything; - .NET Parallel Programming).
                    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 >>>>>>> <florent@flovilmart.com <mailto: >>>>>>> florent@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.kemp@apple.com >>>>>>> <mailto:adam.kemp@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.lovatt@gmail.com <mailto: >>>>>>>> howard.lovatt@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=
awaitloadWebResource("dataprofile.txt")
                       let imageResource=
awaitloadWebResource("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.kemp@apple.com >>>>>>>>> <mailto:adam.kemp@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 >>>>>>>>>> <florent@flovilmart.com >>>>>>>>>> <mailto:florent@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 >>>>>>>>>>>> <jgroff@apple.com <mailto: >>>>>>>>>>>> jgroff@apple.com>> wrote:

                                On Aug 25, 2017, at 12:34 AM,

Howard
                                Lovatt <
howard.lovatt@gmail.com
                                <mailto:
howard.lovatt@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

                        --
                        -- Howard.

_______________________________________________
                        swift-evolution mailing list
                        swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>

https://lists.swift.org/mailman/listinfo/swift-evolution

                    _______________________________________________
                    swift-evolution mailing list
                    swift-evolution@swift.org <mailto:
swift-evolution@swift.org>

https://lists.swift.org/mailman/listinfo/swift-evolution

            _______________________________________________
            swift-evolution mailing list
            swift-evolution@swift.org <mailto:swift-evolution@swift.org
>
            https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

        _______________________________________________
        swift-evolution mailing list
        swift-evolution@swift.org <mailto:swift-evolution@swift.org>
        https://lists.swift.org/mailman/listinfo/swift-evolution

    _______________________________________________
    swift-evolution mailing list
    swift-evolution@swift.org <mailto:swift-evolution@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Two comments:

  1. I don't think `Future` typed arguments and returns are a big deal,
since they give you easy parallelism, timeouts, queue control, and cancel
and you just call `get` when you need a value.

  2. Don't use `Future` typed arguments and returns where you don't want
parallelism etc. EG if say that `processingImage`, `translate`, and
`render` can run serially in the current `Future` and only the downloads
need to be in parallel then none of the three `func`s would accept or
return a `Future`:

let image = preprocessImage(downloadImage().get ?? defaultImage)
let text = translate(downloadText().get ?? defaultText)

render(image, text)

  -- Howard.

···

On 30 August 2017 at 15:29, David Hart <david@hartbit.com> wrote:

I understand. But it’s quite problematic to have to write all Future
returning functions with Future inputs just to be able to support parallel
computations. It’s not how futures are using in C# and JavaScript.

On 30 Aug 2017, at 03:02, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

The signatures would be:

func processImage(_ image: Future<Image>) -> Future<Image>

func translate(_ text: Future<String>) -> Future<Image>

Inside `processImage` and `translate` you would `get` the values at the
point were needed so that downloadImage and downloadText run in parallel
(which is highly desirable).

  -- Howard.

On 30 August 2017 at 07:21, David Hart <david@hartbit.com> wrote:

I don’t think the examples are 100% equivalent. In your version with the
Future library, *preprocessImage* and *translate* need to accept futures
as argument, correct? That’s more restrictive than in my example code where
async/await specifically provide sugar over *then*. Plus I don’t
understand why you mention that the Future version handles errors when
async/await also plays very nicely with errors.

On 29 Aug 2017, at 10:22, Howard Lovatt <howard.lovatt@gmail.com> wrote:

@David,

Using the `Future` library based on GCD that I have previously posted
your example would be:

let image = preprocessImage(downloadImage()) // These first two lines run in parallellet text = translate(downloadText())render(image: image.get ?? defaultImage, text: text.get ?? defaultText)

The main difference, and I would argue an improvement, is that the
`Future` version handles errors.

So what advantage does async/await have over a `Future` library we can
write today?

  -- Howard.

On 29 August 2017 at 15:28, David Hart via swift-evolution < >> swift-evolution@swift.org> wrote:

On 29 Aug 2017, at 02:22, Xiaodi Wu via swift-evolution < >>> swift-evolution@swift.org> wrote:

On Mon, Aug 28, 2017 at 16:10 Adam Kemp via swift-evolution < >>> swift-evolution@swift.org> wrote:

I know what the proposal said. I’m making a case that there is value in
doing it differently.

The composability of futures is valuable. Mixing and matching
async/await with futures is also valuable. The queue-returning behavior
that you can get from futures is also valuable, and building async/await on
top of futures means async/await can get that for free.

Why couldn't you mix and match async/await and futures and get the
queue-return behavior of futures if futures are built on top of async/await
instead off the other way around?

We could, but the syntax is much worse. Contrast:

*async/await built on top of Futures*

let image = preprocessImage(downloadImage())let text = translate(downloadText())
await render(image: image, text: text)

*Futures built on top of async/await*

let image = Future(downloadImage).then({ preprocessImage($0) })let text = Future(downloadText).then({ translate($0) })
await render(image: image.get(), text: text.get())

Maybe you don’t value those things, which is fine. But I do, and maybe

other people do too. That’s why we’re having a discussion about it.

It can also be valuable having a minimal implementation, but we have to
acknowledge that it comes with a downside as well. The problem with doing a
minimal implementation is that you can be stuck with the consequences for a
long time. I want to make sure that we’re not stuck with the consequences
of a minimal implementation that doesn’t adequately address the problems
that async/await should be addressing. I’d hate for Swift to get an
async/await that is so weak that it has to be augmented by tedious
boilerplate code before it’s useful.

On Aug 28, 2017, at 1:54 PM, Wallacy <wallacyf@gmail.com> wrote:

We don't need to this now!

Again: (Using proposal words)

"It is important to understand that this is proposing compiler support
that is completely concurrency runtime-agnostic. This proposal does not
include a new runtime model (like "actors") - it works just as well with
GCD as with pthreads or another API. Furthermore, unlike designs in other
languages, it is independent of specific coordination mechanisms, such as
futures or channels, allowing these to be built as library feature"

and

"This proposal does not formally propose a Future type, or any other
coordination abstractions. There are many rational designs for futures, and
a lot of experience working with them. On the other hand, there are also
completely different coordination primitives that can be used with this
coroutine design, and incorporating them into this proposal only makes it
larger."

and

We focus on task-based concurrency abstractions commonly encountered in
client and server applications, particularly those that are highly event
driven (e.g. responding to UI events or requests from clients). This does
not attempt to be a comprehensive survey of all possible options, nor does
it attempt to solve all possible problems in the space of concurrency.
Instead, it outlines a single coherent design thread that can be built over
the span of years to incrementally drive Swift to further greatness.

and

This proposal has been kept intentionally minimal, but there are many
possible ways to expand this in the future.

....

The point is: No Future type is indeed proposed yet!

The proposal try to include de "minimum" required to implement a basic
async/await to solve the problem created by the GCD! (Pyramid of doom)

The question is: How do you do the same using dispatch_async ?
dispatch_async also does not return nothing to do what you are intentend do
do!

Algo, by Swift 5 manifesto, there's no compromise to make a "complete"
concurrency model by this time!

My intention is only make parity to dispatch_async, but also make the
ground free to make more complex implementation like Futures in another
round on top of this one.

This 'async T' can be a real type in the future? Maybe will... But
doesn't matter now! Now we only need to is some kind of type which need to
be unwrapped using await before use. Maybe this intermediary/virtual type
can be a real thing and gain some abilities at some point! Maybe a full
Future type, why not?

Em seg, 28 de ago de 2017 às 17:33, Adam Kemp <adam.kemp@apple.com> >>>> escreveu:

How would these anonymous types get composed? If I wanted to implement
a function that takes a collection of futures and wait on it, how would I
do that? That is, how would I implement the equivalent of C#’s Task.WhenAll
and Task.WhenAny methods?

More generally, how do you pass one of these typeless futures to some
other function so that we can do the waiting there?

On Aug 28, 2017, at 1:23 PM, Wallacy <wallacyf@gmail.com> wrote:

And that's why I (and others) are suggesting:

func processImageData1a() async -> Image {
  let dataResource = async loadWebResource("dataprofile.txt") // No
future type here... Just another way to call dispatch_async under the hood.
  let imageResource = async loadWebResource("imagedata.dat")

  // ... other stuff can go here to cover load latency...

  let imageTmp = await decodeImage(dataResource, imageResource) //
Compiles force await call here...
  let imageResult = await dewarpAndCleanupImage(imageTmp)
  return imageResult
}

And now we gain all advantages of async/await again without to handle
with one more type.

Em seg, 28 de ago de 2017 às 17:07, Adam Kemp via swift-evolution < >>>>> swift-evolution@swift.org> escreveu:

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:
await anything; - .NET Parallel Programming).
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 <florent@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.kemp@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.lovatt@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.kemp@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> 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 < >>>>>>> florent@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>, 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> 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 <jgroff@apple.com> wrote:

On Aug 25, 2017, at 12:34 AM, Howard Lovatt < >>>>>>>>> howard.lovatt@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
https://lists.swift.org/mailman/listinfo/swift-evolution

--

-- Howard.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution