# On the proliferation of try (and, soon, await)

**URL:** <https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621>\
**Category:** Discussion\
**Created:** [December 8, 2020, 10:55pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621 "2020-12-08T22:55:50Z")\
**Posts on this page:** 20\
**Page:** 6

<div class="post-metadata">

**Author:** ![Terje](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Terje](https://forums.swift.org/u/Terje)\
**Post date:** [December 13, 2020, 10:59pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/101 "2020-12-13T22:59:32Z")

</div>

> I'm sorry if you took that as some kind of insult; it certainly wasn't intended that way.

Oh, no it wasn’t. It just reminded me more of professors I had who after a 40 year career couldn’t see anymore through a beginners eye. It’s sometimes easy to forget where the road starts. Things are then taken for granted which are actually not that obvious. Like invariants: a concept new to me in this context or at least something I have not consciously thought about.

Talent, (formal) education and mentoring determines in part how fast down the road one can travel. I wanted to push back a little to make sure everyone can still follow at their own pace.

> I actually encouraged readers to ask themselves that question because I _want_ to hear stories like yours, if they're out there.

Telling my story of a self taught programmer is all that I can offer, for what it’s worth. I transitioned from physics research to programmer/R&D role straddling both worlds.

I like Swift. It’s the best language I’ve used thus far out of c, c++, obj-c, python, c#, matlab, pascal, java, php,...  
I have used Swift since the first beta’s. I think it’s a modern well thought out language that aims and succeeds to onboard beginners and progress them towards increasing complexity. I have high hopes that the actor model will simplify asynchronous/concurrent programming and make it more accessible.  
It’s for those reasons I posted, to help keep Swift great.

> There's always a possibility I'm completely misguided, and it's good to have the data points.

With regard to try proliferation and invariants. For beginners, or well, not professional programmers the concept of error handling is more familiar or easier to understand than invariants I think. An error occurs and you got to deal with it. Swift makes it easy to remember to deal with it and if you don’t want to deal with it just use try? In that one-off program that’s thrown out at the end of the day. I think that’s useful and powerful. Reading that file is not going to fail because the path was just hardcoded in. My colleagues want to use it? Fine I’ll add a bit of error handling so they can open any file without crashing. I can even explain them how the app works. Though the conversation could also turn this way:

“Invariants? Wait what? What are those? What do you mean? Can you explain that in like a 5 minutes? I just want to process a file...”

It could very well be that the correct mental model is that of invariants. Invariants are an unfamiliar way of thinking or at least not a concept by that name which I actively think about when programming. It might be a hole in my knowledge that I simply need to patch or it might mean you have an uphill road ahead to onboard programmers like me. Unfortunately I am trailing you on the road so I can’t really tell which case it is.

In turn I hope I didn’t offended you. It certainly wasn’t intended as an attack upon you. Just wanted to show the other end of the spectrum.

---

<div class="post-metadata">

**Author:** ![dabrahams](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dabrahams/32/9815_2.png) [@dabrahams](https://forums.swift.org/u/dabrahams)\
**Post date:** [December 13, 2020, 11:04pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/102 "2020-12-13T23:04:26Z")

</div>

> [@Terje](#):
>
> “Invariants? Wait what? What are those? What do you mean? Can you explain that in like a 5 minutes? I just want to process a file...”

How does my [explanation for novices that never mentions the word](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/99) strike you?

---

<div class="post-metadata">

**Author:** ![Tino](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tino/32/1073_2.png) [@Tino](https://forums.swift.org/u/Tino)\
**Post date:** [December 13, 2020, 11:05pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/103 "2020-12-13T23:05:34Z")

</div>

> [@Douglas\_Gregor](#):
>
> The span between the `async let` and the `await` is where concurrent work happens.

Good — at least this might mean that my naive first reaction ("try to put as much code between `async` and `await` as possible") wasn't completely wrong ;-)

> [@Douglas\_Gregor](#):
>
> I see no path for async/await without the await

That makes a lot of sense — probably even for a non-programmer ;-)  
But maybe there is more `await` necessary?

The concept is about values that are not there (yet), so I see some similarities with values that might be missing (but where waiting doesn't change anything):  
We have a quite heavy syntax to deal with `Optional`, which can cause the same pyramid of doom created by callbacks (`if let`). We also have `map`, which is roundabout as much ceremony as `await` — and then, we have the very concise optional chaining, which reduces everything to a single character.

I guess (hope ;-) `async` won't be as common as optionals, but would would happen if we wouldn't require the `await` in `merge(await leftArray, await rightArray)`?

For me, those specific `await` s are no help, but rather something needed to make the compiler happy… except maybe: There is some duality between `try` / `Result` and `await` / promise. This isn't mentioned in the proposal, but are there plans to turn an (async) parameter into a promise when `await` is skipped?

---

<div class="post-metadata">

**Author:** ![Terje](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Terje](https://forums.swift.org/u/Terje)\
**Post date:** [December 13, 2020, 11:49pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/105 "2020-12-13T23:49:06Z")

</div>

Your explanation is simply enough that I start to understand your point.  
I agree that making the compiler happy is insufficient. That reminds of c++, shudder.

Your explanation builds up to increased complexity, advanced usage and power. Nice :)

However I agree with Matt that it reduces mental load and forces to at least think about error handling.

Would it make sense to enforce all expressions in a `try{...} catch{...`} to throw? Like, okay power user: you have clearly thought this through and you know what you are doing. Adding `try` to the next 10 lines would just be boiler plate so wrap it up in a block. And dear reader, every line in this block can throw so you now know that too but you don’t have to worry about cleaning up afterwards. It has all been taken care of.

An all or nothing approach would keep cognitive load low and reduce boilerplate. Or is that too simplistic on my part?

---

<div class="post-metadata">

**Author:** ![dabrahams](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dabrahams/32/9815_2.png) [@dabrahams](https://forums.swift.org/u/dabrahams)\
**Post date:** [December 14, 2020, 12:01am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/106 "2020-12-14T00:01:40Z")

</div>

> [@Terje](#):
>
> Your explanation is simply enough that I start to understand your point.  
> I agree that making the compiler happy is insufficient. That reminds of c++, shudder.
> 
> Your explanation builds up to increased complexity, advanced usage and power. Nice :)

Thanks, I'm glad it works for you!

> [@Terje](#):
>
> Would it make sense to enforce all expressions in a `try{...} catch{...` } to throw? Like, okay power user: you have clearly thought this through and you know what you are doing. Adding `try` to the next 10 lines would just be boiler plate so wrap it up in a block. And dear reader, every line in this block can throw so you now know that too but you don’t have to worry about cleaning up afterwards. It has all been taken care of.
> 
> An all or nothing approach would keep cognitive load low and reduce boilerplate. Or is that too simplistic on my part?

Well, it's an interesting idea but I think it's probably too heavy a hammer. I'd have to take apart a `try { ... }` block just to put some `print` debugging in it. Or do something awful like

```
false ? throw SomeError() : print("x:", x)

```

It also feels like it's going to undermine the cognitive value I'm trying to add: in these regions, _it really doesn't matter which things throw_. By forcing every statement to throw, we'd be giving the programmer false clues, implying that it does matter. That would just weaken the understanding of error handling that I want to build.

---

<div class="post-metadata">

**Author:** ![Terje](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Terje](https://forums.swift.org/u/Terje)\
**Post date:** [December 14, 2020, 12:13am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/107 "2020-12-14T00:13:08Z")

</div>

Ok. Yes, that would be even worse.

PS, thank you for taking the time to read, consider and reply to my comments.

---

<div class="post-metadata">

**Author:** ![masters3d](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@masters3d](https://forums.swift.org/u/masters3d)\
**Post date:** [December 14, 2020, 6:17am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/108 "2020-12-14T06:17:03Z")

</div>

> [@dabrahams](#):
>
> We've been talking in this thread about giving the programmer control over the granularity of `try` using various forms of `try` block: either `try {...}` or `try do {...}` . _If_ `async` ends up having a similar signal value in the programming model to `try` , consistency could be maintained by allowing `async` to join or replace `try` in those syntaxes.

How about `trying {...}` instead of `try do {...}`? ; not sure about `awaiting {...}` though

---

<div class="post-metadata">

**Author:** ![benjamin.g](https://avatars.discourse-cdn.com/v4/letter/b/9fc29f/32.png) [@benjamin.g](https://forums.swift.org/u/benjamin.g)\
**Post date:** [December 14, 2020, 2:23pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/109 "2020-12-14T14:23:17Z")

</div>

> I don't know; that's _also_ an interesting feature idea, but I think it's different from the one that surfaces invariant-preservation as a first-class thing. There are lots of operations that are non-transactional in case of an error and yet preserve all knowable invariants (sorting an array, for example).

I had something like this in mind, very much inspired by DB transactions (once again, i'm out of my field here, so forgive my naivete), but for that to be more interesting than the "do {} catch" construct, "invariant preservation", or at least some aspect of it, needs to be an orthogonal concept.

```
func updateUser() {
atomic(firstName, lastName) { // captured and reverted to their original values by default in case of failure
 self.firstName = try decode(…) // here try wouldn't add much
 self.lastName = await fetch(…) // here await wouldn't add much (maybe ?)
} rollback {
//lets you get noticed of failure , timeout, etc. and override default rollback behavior 
log(error)
self.firstName = "?" 
self.lastName = "?"
}

```

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [December 14, 2020, 2:57pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/110 "2020-12-14T14:57:45Z")

</div>

@benjamin.g, you can get the effect you're after by modeling the "state-that-you-want-to-update-transactionally" in an standalone struct:

```swift
struct FullName {
    var firstName: String
    var lastName: String
}

var fullName: FullName

func updateUser() async throws {
    // First and last name are set together, or not at all
    fullName = await try FullName(
        firstName: decode(...),
        lastName: fetch(...)
}

```

You may need to add appropriate locking / actorification if thread-safety is required.

---

<div class="post-metadata">

**Author:** ![David\_Catmull](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_catmull/32/1007_2.png) [@David\_Catmull](https://forums.swift.org/u/David_Catmull)\
**Post date:** [December 14, 2020, 4:28pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/111 "2020-12-14T16:28:46Z")

</div>

> [@Tino](#):
>
> Looking at
> 
> > [@Douglas\_Gregor](#):
> >
> > ```swift
> > func mergeSort<T: Comparable>(_ array: [T]) async -> [T] {
> > guard array.count > 1 else { return array }
> > 
> > let middleIndex = array.count / 2
> > 
> > async let leftArray = await mergeSort(Array(array[0..<middleIndex]))
> > async let rightArray = await mergeSort(Array(array[middleIndex..<array.count]))
> > 
> > return merge(await leftArray, await rightArray)
> > }
> > 
> > ```
> 
> I'd say that there is actually some noise: It just looks like regular code, sprinkled with lots of `await`

I actually had the opposite impression. To me, having those `await`s in there to emphasize that there is some kind of asynchronicity is valuable. Otherwise it would be easy to look at it and think it's just a regular merge sort.

Although according to my understanding of async/await, that implementation would not actually benefit from any concurrency. Since the only thing being awaited is the recursive call to `mergeSort`, there's no "real" asynchonicity being introduced. It's telling the compiler "I'm asynchronous because I'm asynchronous" but really it pretty much isn't. As soon as you actually `await` it the entire thing executes, sequentially, recursive calls and all.

---

<div class="post-metadata">

**Author:** ![David\_Catmull](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_catmull/32/1007_2.png) [@David\_Catmull](https://forums.swift.org/u/David_Catmull)\
**Post date:** [December 14, 2020, 4:38pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/112 "2020-12-14T16:38:52Z")

</div>

OK, I read up on `async let` again and it looks like I'm wrong. A task created with `async let` is run concurrently, which I take to mean executed on a different thread, though the proposal doesn't seem to say that explicitly so I'm a little confused. Is that intentionally ambiguous?

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [December 14, 2020, 5:04pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/113 "2020-12-14T17:04:20Z")

</div>

> [@David\_Catmull](#):
>
> A task created with `async let` is run concurrently, which I take to mean executed on a different thread, though the proposal doesn't seem to say that explicitly so I'm a little confused.

The actual scheduling of tasks is delegated to an executor: [https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md#executors](https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md#executors)

So the actual flavor of concurrency will depend on both the async method, and the executor. The phrasing prefers "concurrency" over "parallelism", for multiple reasons:

- As a consumer of an `async` methods with the `await` keyword (or `async let`), the language wants you to think about concurrency more than parallelism or threads ([lexicon](https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism)). For example, an async method is allowed to execute and return synchronously. An async method is allowed to schedule some little jobs on the main RunLoop (think I/O). An async method is allowed to spawn a new thread, or use libDispatch, or use other facilities provided by the new Task and Actor apis.
- `async/await` are more fundamental than [Structured concurrency](https://forums.swift.org/t/concurrency-structured-concurrency/41622) and [Actors](https://forums.swift.org/t/concurrency-actors-actor-isolation/41613), which will, I guess, answer your questions with more details.
- I expect that "don't mismatch `DispatchQueue.async` with Swift's `async`" will soon become a mantra, and a key step in the discovery of the new concurrency features.

---

<div class="post-metadata">

**Author:** ![dabrahams](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dabrahams/32/9815_2.png) [@dabrahams](https://forums.swift.org/u/dabrahams)\
**Post date:** [December 14, 2020, 6:06pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/114 "2020-12-14T18:06:29Z")

</div>

> [@gwendal.roue](#):
>
> The actual scheduling of tasks is delegated to an executor: [https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md#executors](https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md#executors)

But Doug has said that the global executor will run them in parallel (probably on a separate thread but since there's a thread pool behind it, you can't be 100% sure IIUC).

---

<div class="post-metadata">

**Author:** ![nuclearace](https://avatars.discourse-cdn.com/v4/letter/n/51bf81/32.png) [@nuclearace](https://forums.swift.org/u/nuclearace)\
**Post date:** [December 14, 2020, 7:22pm UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/115 "2020-12-14T19:22:02Z")

</div>

This is an important detail of the executor chosen, which may vary between executors. Some `async` users may prefer an executor (assuming one comes along) modeled more along the lines of JavaScript, where there is a single thread that user code gets executed on. This still can provide concurrency, just not parallelism.

Of course this means that users must be aware of the executor that is being used. Now, if a couple of third-party executor libraries become common, then I can start to see this becoming a point of contention among Swift libraries where they only work on some executors and not others, leaving a fractured ecosystem. (Which leads me to ask, should Swift define how executors should behave, to some extent?)

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner3](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/chris_lattner3/32/348_2.png) [@Chris\_Lattner3](https://forums.swift.org/u/Chris_Lattner3)\
**Post date:** [December 16, 2020, 5:53am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/116 "2020-12-16T05:53:27Z")

</div>

> [@dabrahams](#):
>
> OK, I'm really sorry to do this because I am sure you have a lot more experience with `async` than I do, but it _sounds_ like you are [mixing up concurrency and parallelism](https://stackoverflow.com/questions/1050222/what-is-the-difference-between-concurrency-and-parallelism#:~:text=Concurrency%20is%20when%20two%20or,e.g.%2C%20on%20a%20multicore%20processor.). My understanding is that the one thing `async let` is guaranteed to do is introduce concurrency. It was also my understanding that whether it introduces parallelism may depend on the current executor, although available information about the role of executors has been somewhat thin.

Just my 2c, but you're not the only one confused by this. The fundamental issue here is that `async` as proposed by the current async/await model _only_ means concurrency. However, the "structured concurrency" proposal overloads the keyword to "introduce **parallelism**" by spawning a new parallel computation, which confuses the model (as you can see from non-Apple people's incorrect interpretation of the proposed model).

I don't understand why we would reuse that keyword here, particularly as a decl modifier. I would recommend something explicit (e.g. `let myFuture = spawnTask { ... }` or use property wrappers with autoclosure to do `@Spawned let myFuture = ...`) to make it clear that new concurrency units are being created.

If that were untenable for some reason, we should pick another word like `spawn let myFuture = ...` to eliminate the confusion and make it clear that this is a really different thing. This is a decl modifier so we can pick any word without intruding on the keyword namespace.

> [@David\_Catmull](#):
>
> OK, I read up on `async let` again and it looks like I'm wrong. A task created with `async let` is run concurrently, which I take to mean executed on a different thread, though the proposal doesn't seem to say that explicitly so I'm a little confused. Is that intentionally ambiguous?

I'm not sure if it is intentional or not, but I'm not aware of a reason to do this.

-Chris

---

<div class="post-metadata">

**Author:** ![adamkemp](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/adamkemp/32/3017_2.png) [@adamkemp](https://forums.swift.org/u/adamkemp)\
**Post date:** [December 16, 2020, 6:13am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/117 "2020-12-16T06:13:08Z")

</div>

I’m increasingly of the opinion that `async let` should behave the way I at first assumed it did work, which is that it only works with async expressions and doesn’t change at all how the called functions are run. I [asked on the other thread](https://forums.swift.org/t/dougs-concurrent-merge-sort-actor-counters-examples/42773/7) about how a few different examples would run, but I haven’t gotten an answer. I feel like if these two calls work differently then that’s too subtle:

```swift
 // func g() async

// 3
await g()

// 4
async let task = g()
await task

```

IMO those should do the exact same thing. If they don’t then like Chris said there should be a different keyword use to make that clearer, and then there should be a way to split the await from the call site without changing behavior.

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [December 16, 2020, 6:28am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/118 "2020-12-16T06:28:38Z")

</div>

> [@Chris\_Lattner3](#):
>
> However, the "structured concurrency" proposal overloads the keyword to "introduce **parallelism**" by spawning a new parallel computation, which confuses the model (as you can see from non-Apple people's incorrect interpretation of the proposed model).

I’m sorry but structured concurrency is about concurrency.

As the Structured Concurrency proposal states in its first paragraphs, async/await by itself does not _really_ achieve concurrency, but forces the execution to be sequential (suspending instead of blocking, but semantically”sequential”) and structured concurrency introduces the notion of concurrency, which in turn, _enables_ executors to execute these concurrent “pieces of a program” to run in parallel, if it can and wishes to do so.

It’s the same usual story of: since it introduces concurrency it allows for those concurrent pieces to be executed in parallel, and it just-so-happens that default executors are generally assumed to be multi threaded and as such, would take advantage of this and run these (e.g. async tasks or tasks launched into a task group) in parallel.

There is no inherent promise or need that child tasks will be parallel though. All those concepts work perfectly fine in a single threaded runtime. In practice, yeah, they will often be — that’s why we structure our programs with concurrency in mind. But how parallel or not at all they are, is a different “plane” entirely.

New sugar or keywords might be nice though; Though I may be biased by the work on task groups, which become very verbose (but also... are a low level building block, so maybe that’s fine?), as launching tasks in them becomes `await group.add { await thing() }`, for such I agree it would be nice to `launch { ... }` and automatically attach to the current task; If it is a group, dropping the reference to the task would be allowed, since it is possible to collect the completions independently, if the parent is not a group... they would have to be stored. I’m not sure if this is a simpler or harder model to reason about to be honest though.

> [@Chris\_Lattner3](#):
>
> > [@David\_Catmull](#):
> >
> > OK, I read up on `async let` again and it looks like I'm wrong. A task created with `async let` is run concurrently, which I take to mean executed on a different thread, though the proposal doesn't seem to say that explicitly so I'm a little confused. Is that intentionally ambiguous?
> 
> I'm not sure if it is intentional or not, but I'm not aware of a reason to do this.

It is ambigious because it would be wrong to strictly define it — on runtimes which are not multi threaded, these would not execute in parallel.

On runtimes (or executor configurations) which can and want to to leverage parallelism — these are the the “pieces” that _might_ be executed in parallel. The amount of parallelism is _not_ exactly 1:1 with what the source expresses; it can only express the concurrent “skeleton” of the execution.

---

<div class="post-metadata">

**Author:** ![Chris\_Lattner3](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/chris_lattner3/32/348_2.png) [@Chris\_Lattner3](https://forums.swift.org/u/Chris_Lattner3)\
**Post date:** [December 16, 2020, 7:00am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/119 "2020-12-16T07:00:32Z")

</div>

> [@ktoso](#):
>
> I’m sorry but structured concurrency is about concurrency.
> 
> As the Structured Concurrency proposal states in its first paragraphs, async/await by itself does not _really_ achieve concurrency, but forces the execution to be sequential (suspending instead of blocking, but semantically”sequential”) and structured concurrency introduces the notion of concurrency, which in turn, _enables_ executors to execute these concurrent “pieces of a program” to run in parallel, if it can and wishes to do so.

I think I understand what you are trying to convey, but this explanation doesn't make sense to me. The language model allows executors of different kinds, ones which are implemented serially and ones that are implemented with parallelism. As such, the language model has to be that "pieces of programs" scheduled onto an executor "could" introduce parallelism. As such, I'd summarize the situation as:

1. Async/await themselves don't introduce parallelism. It is a simple state machine transformation that allows functions to be suspended. I don't think this is controversial.

2. The structured concurrency proposal provides (more than one) way to put async units of code onto executors, which **potentially introduces parallelism**. One of these is the `async let` proposal, which puts computation onto an executor, potentially introducing concurrency.

I think you're arguing with the second part. Do you disagree that this potentially introduces parallelism into the program, or am I wrong about part #1?

> [@ktoso](#):
>
> New sugar or keywords might be nice though

Sure, but "might be nice" isn't really the bar to meet. I'd recommend introducing the language and library model without the sugar. Once we understand and accept it we can look at the specific contribution of the sugar, separated from the general contribution of the structured concurrency model (which is a huge progression even in the absence of the sugar). Separating out the concerns helps to evaluate and nudge the various pieces in the right direction independently.

We always know we can add sugar later to many things in the language, but that is usually a more nuanced discussion than the programming model engendered by the larger proposal.

> [@ktoso](#):
>
> It is ambigious because it would be wrong to strictly define it — on runtimes which are not multi threaded, these would not execute in parallel.
> 
> On runtimes (or executor configurations) which can and want to to leverage parallelism — these are the the “pieces” that _might_ be executed in parallel. The amount of parallelism is _not_ exactly 1:1 with what the source expresses; it can only express the concurrent “skeleton” of the execution.

I don't follow this argument. By a similar argument, we shouldn't require "async" because not every invocation will suspend. The question is "what should programmers be forced to anticipate"?

If the executor is "allowed to" implement this with a parallel execution model, then all programmers will be expected to cope with the complexity that that implies, including race conditions or `ActorSendable` depending on the other design points chosen for the model.

-Chris

---

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [December 16, 2020, 7:18am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/120 "2020-12-16T07:18:20Z")

</div>

> [@Chris\_Lattner3](#):
>
> As such, the language model has to be that "pieces of programs" scheduled onto an executor "could" introduce parallelism. As such, I'd summarize the situation as:
> 
> 1. Async/await themselves don't introduce parallelism. It is a simple state machine transformation that allows functions to be suspended. I don't think this is controversial.
> 2. The structured concurrency proposal provides (more than one) way to put async units of code onto executors, which **potentially introduces parallelism**. One of these is the `async let` proposal, which puts computation onto an executor, potentially introducing concurrency.
> 
> I think you're arguing with the second part. Do you disagree that this potentially introduces parallelism into the program, or am I wrong about part #1?

My argument is that the proposal and features of Structured Concurrency _do not_ conflate the terms, and that some statements in this thread add to the confusion, thus the clarification attempt.

Specifically the phrasing of:

> [@Chris\_Lattner3](#):
>
> However, the "structured concurrency" proposal overloads the keyword to "introduce **parallelism**" by spawning a new parallel computation, which confuses the model

is very misleading and confusing people reading the proposals and this thread, by muddying the waters.

You now, correctly, added the "potentially" word to the statements:

> [@Chris\_Lattner3](#):
>
> 1. Async/await themselves don't introduce parallelism. It is a simple state machine transformation that allows functions to be suspended. I don't think this is controversial.
> 2. The structured concurrency proposal provides (more than one) way to put async units of code onto executors, which **potentially** introduces parallelism. One of these is the `async let` proposal, which puts computation onto an executor, potentially introducing concurrency.

Which is makes the statement correct, while the previous one was highly misleading.

And then again... "potentially parallel" is _exactly_ what _concurrency_ is, thus proving and confirming that structured concurrency does not really introduce or speak in terms of parallelism, but merely concurrency.

All I'm saying that the previous statements made here were very confusing and seeing how people in this thread are getting more confused by this thread it necessary to clarify and state what expresses what correctly.

So Dave's take on it, as well as your _corrected_ (1 + 2) statements express the semantics better, and hopefully my clarification will also help other readers of this thread.

> [@dabrahams](#):
>
> [...] the one thing `async let` is guaranteed to do is introduce concurrency. It was also my understanding that whether it introduces parallelism may depend on the current executor, although available information about the role of executors has been somewhat thin.

* * *

> [@Chris\_Lattner3](#):
>
> > [@ktoso](#):
> >
> > New sugar or keywords might be nice though
> 
> Sure, but "might be nice" isn't really the bar to meet. I'd recommend introducing the language and library model without the sugar.

This was in direct follow up to your spelling counter proposal. I'm not actually proposing any such sugar, just saying "yeah, a thing similar to what you mention there might be nice", exactly as you say yourself: might be nice but doesn't meet the bar, so let's ignore for now:

> [@Chris\_Lattner3](#):
>
> I don't understand why we would reuse that keyword here, particularly as a decl modifier. I would recommend something explicit (e.g. `let myFuture = spawnTask { ... }` or use property wrappers with autoclosure to do `@Spawned let myFuture = ...` ) to make it clear that new concurrency units are being created.

just as much sugar as the async let spelling. Doug and the compiler folks are really the ones calling the shot here; but personally, this is really equivalent amounts of sugar and compiler magic needed.

We must enforce that such spawned task must be awaited on, so _however_ it's going to be marked, there still is sugar and magic to enforce that.

> [@Chris\_Lattner3](#):
>
> I don't follow this argument. By a similar argument, we shouldn't require "async" because not every invocation will suspend. The question is "what should programmers be forced to anticipate"?

It's a direct answer to "will it run on a different thread", to which the answer is: assume the worst (that it might). If it helps we can specify that, but that's IMHO why leaving it undefined "how exactly it executes" is pretty much right.

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [December 16, 2020, 7:35am UTC](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621/121 "2020-12-16T07:35:31Z")

</div>

> [@ktoso](#):
>
> It's a direct answer to "will it run on a different thread", to which the answer is: assume the worst (that it might). If it helps we can specify that, but that's IMHO why leaving it undefined "how exactly it executes" is pretty much right.

I find that your explanations are clear, and that drawing limits in the scope of each component of the roadmap is important. Some details that are delegated to a component B are expected to be left "undefined" by another component A. This is all good.

In this thread however, people ask questions that will need to get a precise answer eventually. Actual modes of concurrency have to turn "defined" at some point.

Which pitch of the roadmap will answer those questions? Is it all about executors ? Which ones will ship (default vs. actors, vs. custom, vs others)? What are their precise behavior and guarantees? Can the implementation of an async function control executors? Can an async function manage its concurrency outside of executors (say, using low-level runtime constructs such as threads or dispatch queues)? Is the behavior of one particular async method expected to change depending on the context it is called from (say from the default global one, or from an actor)?

[Previous page](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621.md?page=5)

[Next page](https://forums.swift.org/t/on-the-proliferation-of-try-and-soon-await/42621.md?page=7)
