Skip to content

Instantly share code, notes, and snippets.

@kkpan11
Forked from lattner/TaskConcurrencyManifesto.md
Created November 24, 2023 21:22
Show Gist options
  • Save kkpan11/f49d7c4591b42639ee9dda46be2e6952 to your computer and use it in GitHub Desktop.
Save kkpan11/f49d7c4591b42639ee9dda46be2e6952 to your computer and use it in GitHub Desktop.

Revisions

  1. @lattner lattner revised this gist Oct 13, 2019. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,8 @@

    Author: [Chris Lattner](https://github.com/lattner)

    [Chinese Translation](https://gist.github.com/yxztj/7744e97eaf8031d673338027d89eea76) by [Jason Yu](https://github.com/yxztj)

    ## Contents

    - [Introduction](#introduction)
  2. @lattner lattner revised this gist Oct 20, 2018. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -374,9 +374,7 @@ which we briefly explore.
    ## Part 1: Async/await: beautiful asynchronous APIs

    NOTE: This section is concrete enough to have a [fully baked
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619). From a
    complexity perspective, it is plausible to get into Swift 5, we just need to determine whether
    it is desirable, then if so, debate and refine the proposal as a community.
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619) with more details.

    No matter what global concurrency model is settled on for Swift, it is hard to ignore the
    glaring problems we have dealing with asynchronous APIs. Asynchronicity is unavoidable
  3. @lattner lattner revised this gist Oct 19, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Concurrency in Swift: One approach
    # Swift Concurrency Manifesto

    Author: [Chris Lattner](https://github.com/lattner)

  4. @lattner lattner revised this gist Sep 12, 2017. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -337,7 +337,11 @@ primitives that computation is built on, and reflect the basic abstraction of CP
    Asynchrony is the next fundamental abstraction that must be tackled in Swift, because it is
    essential to programming in the real world where we are talking to other machines, to slow
    devices (spinning disks are still a thing!), and looking to achieve concurrency between multiple
    independent operations. Fortunately, Swift is not the first language to face
    independent operations. Furthermore, latency of apparently identical operations is sometimes
    subject to significant jitter, examples include: networks dropping a packet (retry after
    timeout) and by fast path/slow path optimizations (e.g. caches).

    Fortunately, Swift is not the first language to face
    these challenges: the industry as a whole has fought this dragon and settled on
    [async/await](https://en.wikipedia.org/wiki/Await) as the right abstraction. We propose
    adopting this proven concept outright (with a Swift spin on the syntax). Adopting
    @@ -740,14 +744,14 @@ implement the requirement) properly, or else they cannot be passed as a paramete
    of an `actor` method. In the author's opinion, giving classes proper value semantics will not
    be that big of a deal in practice for a number of reasons:

    - A number of classes in Cocoa are already semantically immutable, making it trivial and
    cheap for them to conform.
    - The default (non-conformance) is the right default: the only classes that conform will be
    ones that a human thought about.
    - Retroactive conformance allows app developers to handle cases not addressed by the
    framework engineers.
    - Cocoa has a number of classes (e.g. the entire UI frameworks) that are only usable on the
    main thread. By definition, these won't get passed around.
    - A number of classes in Cocoa are already semantically immutable, making it trivial and
    cheap for them to conform.

    Beyond that, when you start working with an actor system, it is an inherent part of the
    application design that you don't allocate and pass around big object graphs: you allocate
  5. @lattner lattner revised this gist Sep 4, 2017. 1 changed file with 12 additions and 6 deletions.
    18 changes: 12 additions & 6 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -822,15 +822,20 @@ Here are some potential issues using GCD which we will need to be figure out:

    **Kernel Thread Explosions**

    One concern is that GCD can be subject to kernel thread explosions, which occur when a
    task blocks in a way that the kernel and runtime cannot reason about. In response,
    Our goal is to allow actors to be used as a core unit of abstraction within a program, which
    means that we want programmers to be able to create as many of them as they want, without
    running into performance problems. If scalability problems come up, you end up having to
    aggregate logically distinct stuff together to reduce # actors, which leads to complexity
    and loses some of the advantages of data isolation. The model as proposed should scale
    exceptionally well, but depends on the runtime to make this happen in practice.

    GCD is already quite scalable, but one concern is that it can be subject to kernel thread
    explosions, which occur when a
    GCD task blocks in a way that the kernel and runtime cannot reason about. In response,
    the GCD runtime allocates new kernel threads, each of which get a stack... and these stacks
    can fragment the heap. This is problematic in the case
    of a server workload that wants to instantiate hundreds of thousands of actors - at
    least one for every incoming network connection. The programming model is substantially
    harmed when you have to be afraid of creating too many actors: you have to start
    aggregating logically distinct stuff together to reduce # queues, which leads to complexity
    and loses some of the advantages of data isolation.
    least one for every incoming network connection.

    Provably solving thread explosions is probably impossible/impractical in any runtime given
    the need to interoperate with C code and legacy systems that aren't built in pure Swift. That
    @@ -916,6 +921,7 @@ few other common abstractions. For example:

    - [Reactive streams](https://en.wikipedia.org/wiki/Reactive_Streams) is a common way to
    handle communication between async actors, and helps provide solutions to backpressure.
    [Dart's stream design](https://www.dartlang.org/tutorials/language/streams) is one example.

    - Relatedly, it makes sense to extend the `for/in` loop to asynchronous sequences - likely through the introduction of
    a new `AsyncSequence` protocol. FWIW, this is likely to be added to
  6. @lattner lattner revised this gist Sep 3, 2017. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -953,6 +953,11 @@ interesting to consider for a number of reasons:

    - Something like this would also probably be the right abstraction for imported RPC services
    that allow for multiple concurrent synchronous requests.

    - This abstraction would be unsafe from the memory safety perspective, but this is widely
    precedented in Swift. Many safe abstractions are built on top of memory unsafe
    primitives - consider how `Array` is built on `UnsafePointer` - and this is an important
    part of the pragmatism and "get stuff done" nature of the Swift programming model.

    That said, this is definitely a power-user feature, and we should understand, build, and get
    experience using the basic system before considering adding something like this.
  7. @lattner lattner revised this gist Sep 3, 2017. 1 changed file with 34 additions and 3 deletions.
    37 changes: 34 additions & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -820,7 +820,7 @@ advanced features by giving every actor a `gimmeYourQueue()` method.

    Here are some potential issues using GCD which we will need to be figure out:

    *Kernel Thread Explosions*
    **Kernel Thread Explosions**

    One concern is that GCD can be subject to kernel thread explosions, which occur when a
    task blocks in a way that the kernel and runtime cannot reason about. In response,
    @@ -851,14 +851,14 @@ particularly well for server workloads, which are the ones most likely to need a
    actors at a single time. Legacy server libraries are also much more likely to be async friendly
    than arbitrary other C code.

    *Actor Shutdown*
    **Actor Shutdown**

    There are also questions about how actors are shut down. The conceptually ideal model is
    that actors are implicitly released when their reference count drops to zero and when the last
    enqueued message is completed. This will probably require some amount of runtime
    integration.

    *Bounded Queue Depths*
    **Bounded Queue Depths**

    Another potential concern is that GCD queues have unbounded depth: if you have a
    producer/consumer situation, a fast producer can outpace the consumer and continuously
    @@ -926,6 +926,37 @@ few other common abstractions. For example:
    but it is still a very useful abstraction for handling cases where you want to kick off simple
    overlapping computations within a function.

    ### Intra-actor concurrency

    Another advanced concept that could be considered is allowing someone to define a
    "multithreaded actor", which provides a standard actor API, but where synchronization and
    scheduling of tasks is handled by the actor itself, using traditional synchronization
    abstractions instead of a GCD queue. Adding this would mean that there is shared mutable
    state *within* the actor, but that isolation *between* actors is still preserved. This is
    interesting to consider for a number of reasons:

    - This allows the programming model to be consistent (where an "instance of an actor
    represents a thing") even when the thing can be implemented with internal concurrency.
    For example, consider an abstraction for a network card/stack: it may want to do its own
    internal scheduling and prioritizing of many different active pieces of work according to its
    own policies, but provide a simple-to-use actor API on top if that. The fact that the actor
    can handle multiple concurrent requests is an implementation detail the clients shouldn’t
    have to be rewritten to understand.

    - Making this non-default would provide proper progressive disclosure of complexity.

    - You’d still get improved safety and isolation of the system as a whole, even if individual actors are “optimized” in this way.

    - When incrementally migrating code to the actor model, this would make it much easier to
    provide actor wrappers for existing concurrent subsystems built on shared mutable state
    (e.g. a database whose APIs are threadsafe).

    - Something like this would also probably be the right abstraction for imported RPC services
    that allow for multiple concurrent synchronous requests.

    That said, this is definitely a power-user feature, and we should understand, build, and get
    experience using the basic system before considering adding something like this.


    ## Part 3: Reliability through fault isolation

  8. @lattner lattner revised this gist Sep 3, 2017. 1 changed file with 38 additions and 4 deletions.
    42 changes: 38 additions & 4 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -810,28 +810,62 @@ should eliminate the most obvious bugs.
    ### Scalable Runtime

    Thus far, we've dodged the question about how the actor runtime should be implemented.
    This is intentional because I'm not a runtime expert! From my perspective, GCD is a
    This is intentional because I'm not a runtime expert! From my perspective, building on top
    of GCD is great if it can work for us, because it is proven and using it reduces risk from the
    concurrency design. I also think that GCD is a
    reasonable baseline to start from: it provides the right semantics, it has good low-level
    performance, and it has advanced features like Quality of Service support which are just as
    useful for actors as they are for anything else. It would be easy to provide access to these
    advanced features by giving every actor a `gimmeYourQueue()` method.

    The one problem I anticipate with GCD is that it doesn't scale well enough: server developers
    in particular will want to instantiate hundreds of thousands of actors in their application, at
    Here are some potential issues using GCD which we will need to be figure out:

    *Kernel Thread Explosions*

    One concern is that GCD can be subject to kernel thread explosions, which occur when a
    task blocks in a way that the kernel and runtime cannot reason about. In response,
    the GCD runtime allocates new kernel threads, each of which get a stack... and these stacks
    can fragment the heap. This is problematic in the case
    of a server workload that wants to instantiate hundreds of thousands of actors - at
    least one for every incoming network connection. The programming model is substantially
    harmed when you have to be afraid of creating too many actors: you have to start
    aggregating logically distinct stuff together to reduce # queues, which leads to complexity
    and loses some of the advantages of data isolation.

    Provably solving thread explosions is probably impossible/impractical in any runtime given
    the need to interoperate with C code and legacy systems that aren't built in pure Swift. That
    said, perfection isn't necessary: we just need a path that moves towards it, and provides
    programmers a way to "get their job done" when an uncooperative framework or API is hit
    in practice. I'd suggest a three step approach to resolving this:

    - Make existing frameworks incrementally "async safe" over time. Ensure that new APIs are
    done right, and make sure that no existing APIs ever go from “async safe” to “async unsafe”.
    - Provide a mechanism that developers can use to address problematic APIs that they
    encounter in practice. It should be something akin to “wrap your calls in a closure and
    pass it to a special GCD function”, or something else of similar complexity.
    - Continue to improve perf and debugger tools to help identify problematic cases that occur
    in practice.

    This approach of focusing on problematic APIs that developers hit in practice should work
    particularly well for server workloads, which are the ones most likely to need a large number of
    actors at a single time. Legacy server libraries are also much more likely to be async friendly
    than arbitrary other C code.

    *Actor Shutdown*

    There are also questions about how actors are shut down. The conceptually ideal model is
    that actors are implicitly released when their reference count drops to zero and when the last
    enqueued message is completed. This will probably require some amount of runtime
    integration.

    *Bounded Queue Depths*

    Another potential concern is that GCD queues have unbounded depth: if you have a
    producer/consumer situation, a fast producer can outpace the consumer and continuously
    grow the queue of work. It would be interesting to investigate options for
    providing bounded queues that throttle or block the producer in this sort of situation.
    providing bounded queues that throttle or block the producer in this sort of situation. Another
    option is to make this purely an API problem, encouraging the use of reactive streams and
    other abstractions that provide back pressure.

    ### Alternative Design: Actors as classes

  9. @lattner lattner revised this gist Sep 3, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Concurrency in Swift: One possible approach
    # Concurrency in Swift: One approach

    Author: [Chris Lattner](https://github.com/lattner)

  10. @lattner lattner revised this gist Aug 29, 2017. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -883,14 +883,14 @@ few other common abstractions. For example:
    - [Reactive streams](https://en.wikipedia.org/wiki/Reactive_Streams) is a common way to
    handle communication between async actors, and helps provide solutions to backpressure.

    - Relatedly, extending the `for/in` loop to asynchronous sequences - likely through the introduction of
    a new `AsyncSequence` (or whatever) protocol. FWIW, this is likely to be added to
    - Relatedly, it makes sense to extend the `for/in` loop to asynchronous sequences - likely through the introduction of
    a new `AsyncSequence` protocol. FWIW, this is likely to be added to
    [C# 8.0](https://channel9.msdn.com/Blogs/Seth-Juarez/A-Preview-of-C-8-with-Mads-Torgersen#time=16m30s).

    - A first class `Future` type is commonly requested. While I expect the importance of it is
    to be far less than in other languages (given the proposed async/await design), it is still a
    very useful abstraction for handling cases where you want to kick off simple overlapping
    computations within a function.
    - A first class `Future` type is commonly requested. I expect the importance of it
    to be far less than in languages that don't have (or who started without) async/await,
    but it is still a very useful abstraction for handling cases where you want to kick off simple
    overlapping computations within a function.


    ## Part 3: Reliability through fault isolation
  11. @lattner lattner revised this gist Aug 29, 2017. 1 changed file with 17 additions and 3 deletions.
    20 changes: 17 additions & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -874,10 +874,24 @@ base class be `Actor`:
    class DataModel : Actor { ... }
    ```

    #### Examples
    ### Further extensions

    The design sketch above is the minimal but important step forward to build concurrency
    abstractions into the language, but really filling out the model will almost certainly require a
    few other common abstractions. For example:

    - [Reactive streams](https://en.wikipedia.org/wiki/Reactive_Streams) is a common way to
    handle communication between async actors, and helps provide solutions to backpressure.

    - Relatedly, extending the `for/in` loop to asynchronous sequences - likely through the introduction of
    a new `AsyncSequence` (or whatever) protocol. FWIW, this is likely to be added to
    [C# 8.0](https://channel9.msdn.com/Blogs/Seth-Juarez/A-Preview-of-C-8-with-Mads-Torgersen#time=16m30s).

    - A first class `Future` type is commonly requested. While I expect the importance of it is
    to be far less than in other languages (given the proposed async/await design), it is still a
    very useful abstraction for handling cases where you want to kick off simple overlapping
    computations within a function.

    NOTE: This section should be expanded to show some of the more common design patterns
    so people have more of an intuitive feel of how things work. Suggestions are welcome!

    ## Part 3: Reliability through fault isolation

  12. @lattner lattner revised this gist Aug 20, 2017. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    Author: [Chris Lattner](https://github.com/lattner)

    ## Contents:
    ## Contents

    - [Introduction](#introduction)
    - [Overall Vision](#overall-vision)
    @@ -1177,8 +1177,7 @@ language](https://www.ponylang.org). It is actor-based and uses them along with
    to provide a type-safe, memory-safe, deadlock-free, and datarace-free programming model.
    The biggest
    semantic difference between the Pony design and the Swift design is that Pony invests a
    lot of design complexity into providing [capability-based
    security](https://en.wikipedia.org/wiki/Capability-based_security), which impose a high
    lot of design complexity into providing reference capabilities, which impose a high
    learning curve. In contrast, the model proposed here builds on Swift's mature system of
    value semantics. If transferring object graphs between actors (in a guaranteed memory safe
    way) becomes important in the future, we can investigate expanding the [Swift Ownership
  13. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 7 additions and 6 deletions.
    13 changes: 7 additions & 6 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,13 @@
    # Concurrency in Swift: One possible approach

    * Author: [Chris Lattner](https://github.com/lattner)
    Author: [Chris Lattner](https://github.com/lattner)

    ## Contents:

    Contents:
    - [Introduction](#introduction)
    - [Overall Vision](#overall-vision)
    - [Part 1: Async/await](#part-1-asyncawait)
    - [Part 2: Actors](#part-2-actors)
    - [Part 1: Async/await: Beautiful asynchronous APIs](#part-1-asyncawait-beautiful-asynchronous-apis)
    - [Part 2: Actors: Eliminating shared mutable state](#part-2-actors-eliminating-shared-mutable-state)
    - [Part 3: Reliability through fault isolation](#part-3-reliability-through-fault-isolation)
    - [Part 4: Improving system architecture](#part-4-improving-system-architecture)
    - [Part 5: The crazy and brilliant future](#part-5-the-crazy-and-brilliant-future)
    @@ -366,7 +367,7 @@ message sends. This can extrapolate out to a number of interesting long term po
    which we briefly explore.


    ## Part 1: Async/await
    ## Part 1: Async/await: beautiful asynchronous APIs

    NOTE: This section is concrete enough to have a [fully baked
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619). From a
    @@ -457,7 +458,7 @@ asynchronous file I/O API). The [Server APIs Project](https://swift.org/server-
    actively working to define new Swift APIs, many of which are intrinsically asynchronous.


    ## Part 2: Actors
    ## Part 2: Actors: Eliminating shared mutable state

    Given the ability define and use asynchronous APIs with expressive "imperative style" control
    flow, we now look to give developers a way to carve up their application into multiple
  14. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 14 additions and 8 deletions.
    22 changes: 14 additions & 8 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -301,7 +301,7 @@ affairs. A better world would be for app developers to have a way to
    build their data abstractions, concurrency abstractions, and reason about their
    application in the large, even if it is running across multiple machines in a cloud ecosystem.
    If you want your single process app to start running in an IPC or distributed setting, you
    should only have to teach your types how to serialize/🐟 themselves, deal with new
    should only have to teach your types how to serialize/code themselves, deal with new
    errors that can arise, then configure where you want each bit of code to run. You shouldn't
    have to rewrite large parts of the application - certainly not with an entirely new technology
    stack.
    @@ -389,7 +389,7 @@ handling awkward, and make control flow extremely difficult.
    There is a well-known solution to this problem, called
    [async/await](https://en.wikipedia.org/wiki/Await). It is a popular programming style that
    was first introduced in C# and was later adopted in many other languages, including Python,
    Javascript, Scala, Hack, Dart, Kotlin, etc. Given its widespread success and acceptance
    Javascript, Scala, Hack, Dart, etc. Given its widespread success and acceptance
    by the industry, I suggest that we do the obvious thing and support this in Swift.

    ### async/await design for Swift
    @@ -618,11 +618,10 @@ accessors to `throw` or be `async`. When this limitation is relaxed, it would b
    straight-forward to allow `actor var`s to provide the more natural API.

    Note that this extension makes the model far more usable in cases like this, but erodes the
    "deadlock free" guarantee of the actor model. Continuing the analogy that each actor is
    backed by a GCD queue, an await on an `actor` method becomes analogous to calling
    `dispatch_sync` on that queue. Because only one message is processed by the actor at a
    time, if an actor waits on itself directly (possibly through a chain of references) a deadlock will
    occur - in exactly the same way as it happens with `dispatch_sync`:
    "deadlock free" guarantee of the actor model. An await on an `actor` method suspends the
    current task, and since you can get circular waits, you can end up with deadlock. This is
    because only one message is processed by the actor at a time. The simples case occurs
    if an actor waits on itself directly (possibly through a chain of references):

    ```swift
    extension TableModel {
    @@ -867,6 +866,12 @@ e.g.:
    actor class DataModel : SomeBaseActor { ... }
    ```

    alternatively, since you can't derive from non-actor classes anyway, we could just make the
    base class be `Actor`:

    ```swift
    class DataModel : Actor { ... }
    ```

    #### Examples

    @@ -915,7 +920,8 @@ to a restarted instance of the server process.
    The introduction of actors is a great opportunity to improve this situation, because actors
    provide an interesting granularity level between the "whole process" and "an individual class"
    where programmers think about the invariants they are maintaining. Indeed, there is a bunch
    of prior art in making reliable actor systems, and again, Erlang is one of the leaders. We'll
    of prior art in making reliable actor systems, and again, Erlang is one of the leaders (for a
    great discussion, see [Joe Armstrong's PhD thesis](http://erlang.org/download/armstrong_thesis_2003.pdf)). We'll
    start by sketching the basic model, then talk about a potential design approach.

    ### Actor Reliability Model
  15. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -3,14 +3,14 @@
    * Author: [Chris Lattner](https://github.com/lattner)

    Contents:
    - [#introduction](Introduction)
    - [#overall-vision](Overall Vision)
    - [#part-1-asyncawait](Part 1: Async/await)
    - [#part-2-actors](Part 2: Actors)
    - [#part-3-reliability-through-fault-isolation](Part 3: Reliability through fault isolation)
    - [#part-4-improving-system-architecture](Part 4: Improving system architecture)
    - [#part-5-the-crazy-and-brilliant-future](Part 5: The crazy and brilliant future)
    - [#learning-from-other-concurrency-designs](Learning from other concurrency designs)
    - [Introduction](#introduction)
    - [Overall Vision](#overall-vision)
    - [Part 1: Async/await](#part-1-asyncawait)
    - [Part 2: Actors](#part-2-actors)
    - [Part 3: Reliability through fault isolation](#part-3-reliability-through-fault-isolation)
    - [Part 4: Improving system architecture](#part-4-improving-system-architecture)
    - [Part 5: The crazy and brilliant future](#part-5-the-crazy-and-brilliant-future)
    - [Learning from other concurrency designs](#learning-from-other-concurrency-designs)

    ## Introduction

  16. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 12 additions and 1 deletion.
    13 changes: 12 additions & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,16 @@

    * Author: [Chris Lattner](https://github.com/lattner)

    Contents:
    - [#introduction](Introduction)
    - [#overall-vision](Overall Vision)
    - [#part-1-asyncawait](Part 1: Async/await)
    - [#part-2-actors](Part 2: Actors)
    - [#part-3-reliability-through-fault-isolation](Part 3: Reliability through fault isolation)
    - [#part-4-improving-system-architecture](Part 4: Improving system architecture)
    - [#part-5-the-crazy-and-brilliant-future](Part 5: The crazy and brilliant future)
    - [#learning-from-other-concurrency-designs](Learning from other concurrency designs)

    ## Introduction

    This document is published in the style of a "Swift evolution manifesto", outlining a long-term
    @@ -541,7 +551,8 @@ might look something like this:
    // if so, it capitalize the string before returning it to encourage
    // capitalization consistency in the list.
    func prettify(_ x : String) -> String {
    // ... details omitted, it just pokes theList directly ...
    // Details omitted: it inspects theList, adjusting the
    // string before returning it if necessary.
    }

    actor func add(entry: String) {
  17. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -138,7 +138,7 @@ func processImageData2(completionBlock: (result: Image?, error: Error?) -> Void)
    completionBlock(nil, error)
    return
    }
    return imageResult
    completionBlock(imageResult)
    }
    }
    }
  18. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -1194,7 +1194,9 @@ which leads to bugs and erosion of the model. Their message loops are also manu
    loops with pattern matching, instead of being automatically dispatched to `actor` methods -
    this leads to somewhat more boilerplate. Akka actor messages are untyped (marshalled
    through an Any), which can lead to surprising bugs and difficulty reasoning about what the
    API of an actor is. Beyond that though, the two models are very comparable - and, no, this
    API of an actor is (though the [Akka
    Typed](http://doc.akka.io/docs/akka/2.5.3/scala/typed.html) research project is exploring
    ways to fix this). Beyond that though, the two models are very comparable - and, no, this
    is not an accident.
    Keeping these differences in mind, we can learn a lot about how well the model works in
  19. @lattner lattner revised this gist Aug 18, 2017. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -348,7 +348,7 @@ Speaking of reliable systems, introducing an actor model is a good opportunity a
    to introduce a mechanism for handling and partially recovering from runtime failures (like
    failed force-unwrap operations, out-of-bounds array accesses, etc). We explore several
    options that are possible to implement and make a recommendation that we think will be a
    good for for UI and server applications.
    good for UI and server applications.

    The final step is to tackle whole system problems by enabling actors to run in different
    processes or even on different machines, while still communicating asynchronously through
    @@ -379,7 +379,7 @@ handling awkward, and make control flow extremely difficult.
    There is a well-known solution to this problem, called
    [async/await](https://en.wikipedia.org/wiki/Await). It is a popular programming style that
    was first introduced in C# and was later adopted in many other languages, including Python,
    Javascript, Scala, Hack, Dart, Kotlin ... etc. Given its widespread success and acceptance
    Javascript, Scala, Hack, Dart, Kotlin, etc. Given its widespread success and acceptance
    by the industry, I suggest that we do the obvious thing and support this in Swift.

    ### async/await design for Swift
    @@ -703,7 +703,7 @@ an existence proof for an answer:
    - The compiler just checks for conformance to the `ValueSemantical` protocol and
    rejects any arguments and return values that do not conform.

    The reiterate, the name `ValueSemantical` really isn't the right name for this: things like
    To reiterate, the name `ValueSemantical` really isn't the right name for this: things like
    `UnsafePointer`, for example, shouldn't conform. Enumerating the possible options and
    evaluating the naming tradeoffs between them is a project for another day though.

  20. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 6 additions and 7 deletions.
    13 changes: 6 additions & 7 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -359,9 +359,9 @@ which we briefly explore.
    ## Part 1: Async/await

    NOTE: This section is concrete enough to have a [fully baked
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619) from a
    complexity perspective, it is plausible to get into Swift 5, we just need to debate and refine it
    as a community.
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619). From a
    complexity perspective, it is plausible to get into Swift 5, we just need to determine whether
    it is desirable, then if so, debate and refine the proposal as a community.

    No matter what global concurrency model is settled on for Swift, it is hard to ignore the
    glaring problems we have dealing with asynchronous APIs. Asynchronicity is unavoidable
    @@ -379,9 +379,8 @@ handling awkward, and make control flow extremely difficult.
    There is a well-known solution to this problem, called
    [async/await](https://en.wikipedia.org/wiki/Await). It is a popular programming style that
    was first introduced in C# and was later adopted in many other languages, including Python,
    Javascript, Scala, Hack, Dart, Kotlin ... etc. Given its widespread acceptance by the industry
    and combined with few other good solutions to these problems, I suggest that we do the
    obvious thing and support this in Swift.
    Javascript, Scala, Hack, Dart, Kotlin ... etc. Given its widespread success and acceptance
    by the industry, I suggest that we do the obvious thing and support this in Swift.

    ### async/await design for Swift

    @@ -424,7 +423,7 @@ func processImageData1() async -> Image {
    let dataResource = await loadWebResource("dataprofile.txt")
    let imageResource = await loadWebResource("imagedata.dat")
    let imageTmp = await decodeImage(dataResource, imageResource)
    let imageResult = await dewarpAndCleanupImage(imageTmp)
    let imageResult = await dewarpAndCleanupImage(imageTmp)
    return imageResult
    }
    ````
  21. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -437,7 +437,8 @@ machines and callback handlers for you.

    Overall, adding this will dramatically improve the experience of working with completion
    handlers, and provides a natural model to compose futures and other APIs on top of.
    More details are contained in the full proposal.
    More details are contained in [the full
    proposal](https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619).

    ### New asynchronous APIs

  22. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 21 additions and 17 deletions.
    38 changes: 21 additions & 17 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -396,14 +396,16 @@ This approach allows the completion handler to be absorbed into the language. F
    before you might write:

    ```swift
    func cutBread(completionBlock: (result: Bread) -> Void) { ... }

    func makeSandwich1(completionBlock: (result: Sandwich) -> Void) {
    cutBread { bread in
    cutCheese { cheese in
    cutHam { ham in
    cutTomato { tomato in
    completionBlock(Sandwich([bread, cheese, ham, tomato]))
    func loadWebResource(_ path: String, completionBlock: (result: Resource) -> Void) { ... }
    func decodeImage(_ r1: Resource, _ r2: Resource, completionBlock: (result: Image) -> Void)
    func dewarpAndCleanupImage(_ i : Image, completionBlock: (result: Image) -> Void)

    func processImageData1(completionBlock: (result: Image) -> Void) {
    loadWebResource("dataprofile.txt") { dataResource in
    loadWebResource("imagedata.dat") { imageResource in
    decodeImage(dataResource, imageResource) { imageTmp in
    dewarpAndCleanupImage(imageTmp) { imageResult in
    completionBlock(imageResult)
    }
    }
    }
    @@ -414,16 +416,18 @@ func makeSandwich1(completionBlock: (result: Sandwich) -> Void) {
    whereas now you can write:

    ```swift
    func cutBread() async -> Bread { ... }

    func makeSandwich1() async -> Sandwich {
    let bread = await cutBread()
    let cheese = await cutCheese()
    let ham = await cutHam()
    let tomato = await cutTomato()
    return Sandwich([bread, cheese, ham, tomato])
    func loadWebResource(_ path: String) async -> Resource
    func decodeImage(_ r1: Resource, _ r2: Resource) async -> Image
    func dewarpAndCleanupImage(_ i : Image) async -> Image

    func processImageData1() async -> Image {
    let dataResource = await loadWebResource("dataprofile.txt")
    let imageResource = await loadWebResource("imagedata.dat")
    let imageTmp = await decodeImage(dataResource, imageResource)
    let imageResult = await dewarpAndCleanupImage(imageTmp)
    return imageResult
    }
    ```
    ````

    `await` is a keyword that works like the existing `try` keyword: it is a noop at runtime, but
    indicate to a maintainer of the code that non-local control flow can happen at that point.
  23. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 16 additions and 16 deletions.
    32 changes: 16 additions & 16 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -101,12 +101,12 @@ Modern Cocoa development involves a lot of asynchronous programming using closur
    There are many problems in this space, including the "pyramid of doom" that frequently occurs:

    ```swift
    func makeSandwich1(completionBlock: (result: Sandwich) -> Void) {
    cutBread { bread in
    cutCheese { cheese in
    cutHam { ham in
    cutTomato { tomato in
    completionBlock(Sandwich([bread, cheese, ham, tomato]))
    func processImageData1(completionBlock: (result: Image) -> Void) {
    loadWebResource("dataprofile.txt") { dataResource in
    loadWebResource("imagedata.dat") { imageResource in
    decodeImage(dataResource, imageResource) { imageTmp in
    dewarpAndCleanupImage(imageTmp) { imageResult in
    completionBlock(imageResult)
    }
    }
    }
    @@ -117,28 +117,28 @@ func makeSandwich1(completionBlock: (result: Sandwich) -> Void) {
    Error handling is particularly ugly, because Swift's natural error handling mechanism cannot be used. You end up with code like this:

    ```swift
    func makeSandwich2(completionBlock: (result: Sandwich?, error: Error?) -> Void) {
    cutBread { bread, error in
    guard let bread = bread else {
    func processImageData2(completionBlock: (result: Image?, error: Error?) -> Void) {
    loadWebResource("dataprofile.txt") { dataResource, error in
    guard let dataResource = dataResource else {
    completionBlock(nil, error)
    return
    }
    cutCheese { cheeseSlice, error in
    guard let cheeseSlice = cheeseSlice else {
    loadWebResource("imagedata.dat") { imageResource, error in
    guard let imageResource = imageResource else {
    completionBlock(nil, error)
    return
    }
    cutHam { hamSlice, error in
    guard let hamSlice = hamSlice else {
    decodeImage(dataResource, imageResource) { imageTmp, error in
    guard let imageTmp = imageTmp else {
    completionBlock(nil, error)
    return
    }
    cutTomato { tomatoSlice in
    guard let tomatoSlice = tomatoSlice else {
    dewarpAndCleanupImage(imageTmp) { imageResult in
    guard let imageResult = imageResult else {
    completionBlock(nil, error)
    return
    }
    completionBlock(Sandwich([bread, cheeseSlice, hamSlice, tomatoSlice]), nil)
    return imageResult
    }
    }
    }
  24. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 36 additions and 23 deletions.
    59 changes: 36 additions & 23 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ closure syntax fit well together, particularly after the major update to the GCD
    While Swift has generally stayed away from concurrency topics, it has made some
    concessions to practicality. For example, ARC reference count operations are atomic,
    allowing references to classes to be shared between threads. Weak references are also
    guaranteed to be thread atomic, copy-on-write (COW) types like Array and String are sharable,
    guaranteed to be thread atomic, Copy-On-Write (🐮) types like Array and String are sharable,
    and the runtime provides some other basic guarantees.

    ### Goals and non-goals of this manifesto
    @@ -497,7 +497,7 @@ To make this work pragmatically in the context of Swift, we need to solve severa
    a model that allows messages to return a value (even if we encourage them not to), which
    requires a way to wait for that value. This is the point of adding async/await.
    - we need to make message sends efficient: relying on a deep copy of each argument is not
    acceptable. Fortunately - and not accidentally - we already have copy-on-write (COW) value
    acceptable. Fortunately - and not accidentally - we already have Copy-On-Write (🐮) value
    types and [move semantics](https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md)
    on the way as a basis to build from. The trick is dealing with reference types, which are
    discussed below.
    @@ -662,7 +662,7 @@ that happens.

    Swift is well positioned to deal with this for a number of reasons: its strong focus on value
    semantics means that copying of these values is a core operation understood and known by
    Swift programmers everywhere. Second, the use of copy-on-write (COW) as an
    Swift programmers everywhere. Second, the use of Copy-On-Write (🐮) as an
    implementation approach fits perfectly with this model. Note how, in the example above,
    the DataModel actor sends a copy of the `theList` array back to the UI thread so it can
    update itself. In Swift, this is a super efficient O(1) operation that does some ARC stuff: it
    @@ -711,6 +711,13 @@ the capabilities system in the [Pony](https://www.ponylang.org/) language). Swi
    provides a model where memory safe APIs (e.g. `Array`) are implemented in terms of memory
    unsafety (e.g. `UnsafePointer`), the approach described here is directly analogous.

    *Alternate Design*: Another approach is to eliminate the requirement from the protocol:
    just use the protocol as a marker, which is applied to types that already have the right
    behavior. When it is necessary to customize the copy operation (e.g. for a reference type),
    the solution would be to box values of that type in a struct that provides the right value
    semantics. This would make it more awkward to conform, but this design eliminates having
    "another kind of copy" operation, and encourages more types to provide value semantics.

    #### Reference types: Classes

    The solution to this is simple: classes need to conform to `ValueSemantical` (and
    @@ -821,26 +828,25 @@ actors have a ton of conceptual overlap with classes. Observe:
    references to them.
    - Subclassing of actors makes just as much sense as subclassing of classes, and would
    work the same way.
    - Some people think that Swift hates classes, here's an opportunity to restore some of their
    former glory.
    - Some people incorrectly think that Swift hates classes: this is an opportunity to restore
    some of their former glory.

    However, actors are not *simple classes*: here are some differences:

    - Only actors can have `actor` methods on them and these methods must have additional
    - Only actors can have `actor` methods on them. These methods have additional
    requirements put on them in order to provide the safety in the programming model we seek.
    - An "actor class" deriving from a "non-actor base class" would have to be illegal, because
    the base class could escape self or escape local state references in an unsafe way.
    - Actor references have certain super-powers like being able to be closed over in closures,
    usable as globals, etc.

    One important pivot-point in discussion is whether subclassing of actors is desirable. If so,
    modeling them as a special kind of class would be a very nice simplifying assumption,
    because a lot of complexity comes in with that (including all the initialization rules etc). If not,
    then defining them as a new kind of type is defensible, because they'd be very simple and
    being a separate type would more easily explain the additional rules imposed on them.

    If we went down the route of making them classes, it makes sense for this to be a modifier
    on the class definition itself, since it fundamentally alters the contract of the class, e.g.:
    Syntactically, if we decided to make them classes, it makes sense for this to be a modifier
    on the class definition itself, since actorhood fundamentally alters the contract of the class,
    e.g.:

    ```swift
    actor class DataModel : SomeBaseActor { ... }
    @@ -854,7 +860,7 @@ so people have more of an intuitive feel of how things work. Suggestions are we

    ## Part 3: Reliability through fault isolation

    Swift has many aspects of its design that encourages programmer errors (i.e. software
    Swift has many aspects of its design that encourages programmer errors (aka software
    bugs :-) to be caught at compile time: a static type system, optionals, encouraging covered
    switch cases, etc. However, some errors may only be caught at runtime, including things like
    out-of-bound array accesses, integer overflows, and force-unwraps of nil.
    @@ -863,7 +869,7 @@ As described in the [Swift Error Handling
    Rationale](https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst), there
    is a tradeoff that must be struck: it doesn't make sense to force programmers to write logic
    to handle every conceivable edge case: even discounting the boilerplate that would generate,
    that logic is likely to itself be poorly tested and therefore subject to bugs. We must carefully
    that logic is likely to itself be poorly tested and therefore full of bugs. We must carefully
    weigh and tradeoff complex issues in order to get a balanced design. These tradeoffs are
    what led to Swift's approach that does force programmers to think about and write code to
    handle all potentially-nil pointer references, but not to have to think about integer overflow on
    @@ -935,12 +941,9 @@ needs to think about more issues, and work slightly harder to achieve that relia
    ### Opting into reliability

    Given that a reliable actor requires more thought than building a simple actor, it is reasonable
    to look for opt-in models that allow progressive disclosure of complexity. An alternate
    approach is to require all actors to face that complexity by baking it in as part of the required
    model, reducing the number of choices a Swift programmer gets-to/has-to make. Both
    approaches have merit, but for the sake of this manifesto, we'll proceed with an opt-in model.

    The first thing you need is a way to opt in. As with actor syntax in general, there are two
    to look for opt-in models that provide [progressive disclosure of
    complexity](https://en.wikipedia.org/wiki/Progressive_disclosure). The first thing
    you need is a way to opt in. As with actor syntax in general, there are two
    broad options: first-class actor syntax or a class declaration modifier, i.e., one of:

    ```swift
    @@ -969,16 +972,26 @@ register a failure handler that attempts to save its data in a side location if

    That said, both approaches are feasible and should be explored in more detail.

    *Alternate design*: An alternate approach is make all actors be "reliable" actors, by making
    the additional constraints a simple part of the actor model. This reduces the number of
    choices a Swift programmer gets-to/has-to make. If the async/await model ends up making
    async imply throwing, then this is probably the right direction, because the `await` on a value
    returning method would be implicitly a `try` marker as well.

    ### Reliability runtime model

    Besides the high level semantic model that the programmer faces, there are also questions
    about what the runtime model is. When an actor crashes: what state is its memory left in?
    How well can the process clean up from the failure? Do we attempt to release memory
    and other resources allocated by that actor? There are multiple possible designs, but I
    about what the runtime model is. When an actor crashes:

    - What state is its memory left in?
    - How well can the process clean up from the failure?
    - Do we attempt to release memory and other resources (like file descriptors) managed by that actor?

    There are multiple possible designs, but I
    advocate for a design where **no cleanup is performed**: if an actor crashes, the runtime
    propagates that error to other actors and runs any recovery handlers (as described in the
    previous section) but that it **should not** attempt to clean up the resources owned by the
    actor.
    previous section) but that it **should not** attempt further clean up the resources owned by
    the actor.

    There are a number of reasons for this, but the most important is that the failed actor just
    violated its own consistency with whatever invalid operation it attempted to perform. At this
  25. @lattner lattner revised this gist Aug 17, 2017. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -778,8 +778,12 @@ In practice, this isn't as bad as it sounds, because the most common operations
    that people use (e.g. `print`) are already internally synchronizing, largely because people are
    already writing multithreaded code. While it would be nice to magically solve this long
    standing problem with legacy systems, I think it is better to just completely ignore it and tell
    developers not to define or use global variables (global `let`s are safe). Perhaps we could
    consider deprecating global `var`s from Swift to further nudge people away from them.
    developers not to define or use global variables (global `let`s are safe).

    All hope is not lost though: Perhaps we could consider deprecating global `var`s from Swift
    to further nudge people away from them. Also, any accesses to unsafe global global mutable
    state from an actor context can and should be warned about. Taking some steps like this
    should eliminate the most obvious bugs.

    ### Scalable Runtime

  26. @lattner lattner revised this gist Aug 16, 2017. 1 changed file with 27 additions and 31 deletions.
    58 changes: 27 additions & 31 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -7,10 +7,10 @@
    This document is published in the style of a "Swift evolution manifesto", outlining a long-term
    view of how to tackle a very large problem. It explores *one possible* approach to adding
    a first-class concurrency model to Swift, in an effort to catalyze positive discussion that leads
    us to a final best-possible design. As such, it isn't an approved or finalized design
    us to a best-possible design. As such, it isn't an approved or finalized design
    prescriptive of what Swift will end up adopting. It is the job of public debate on the open
    source swift-evolution mailing list to discuss and iterate towards that ultimate answer, and
    we may end up with a completely different approach.
    source [swift-evolution mailing list](https://github.com/apple/swift-evolution) to discuss and
    iterate towards that ultimate answer, and we may end up with a completely different approach.

    We focus on task-based concurrency abstractions commonly encountered in client
    and server applications, particularly those that are highly event driven (e.g. responding
    @@ -509,8 +509,8 @@ To make this work pragmatically in the context of Swift, we need to solve severa
    There are several possible ways to manifest the idea of actors into Swift. For the purposes of
    this manifesto, I'll describe them as a new type in Swift because it is the least confusing way
    to explain the ideas and this isn't a formal proposal. I'll note right here up front that this is
    almost certainly the wrong thing to do: the right approach is probably for `Actor` to be a
    special kind of class, a model described below.
    only one possible design: the right approach may be for actors to be a special kind of class,
    a model described below.

    With this design approach, you'd define an actor with the `actor` keyword. An actor can
    have any number of data members declared as instance members, can have normal methods,
    @@ -820,29 +820,28 @@ actors have a ton of conceptual overlap with classes. Observe:
    - Some people think that Swift hates classes, here's an opportunity to restore some of their
    former glory.

    However, actors are not *simple classes*: only actors can have `actor` methods on them,
    and these methods must have additional requirements put on them in order to provide the
    safety in the programming model we seek. Actor references have certain super-powers like
    being able to be closed over in closures, usable as globals, etc.
    However, actors are not *simple classes*: here are some differences:

    Here are two possible ways to support this: first (and my personal preference) is for this to be
    a declaration modifier, e.g.:
    - Only actors can have `actor` methods on them and these methods must have additional
    requirements put on them in order to provide the safety in the programming model we seek.
    - An "actor class" deriving from a "non-actor base class" would have to be illegal, because
    the base class could escape self or escape local state references in an unsafe way.
    - Actor references have certain super-powers like being able to be closed over in closures,
    usable as globals, etc.

    ```swift
    actor class DataModel : SomeBaseClass { ... }
    ```
    One important pivot-point in discussion is whether subclassing of actors is desirable. If so,
    modeling them as a special kind of class would be a very nice simplifying assumption,
    because a lot of complexity comes in with that (including all the initialization rules etc). If not,
    then defining them as a new kind of type is defensible, because they'd be very simple and
    being a separate type would more easily explain the additional rules imposed on them.

    An alternate approach is for `Actor` to be a classbound protocol, which has compiler magic
    that injects the dispatch queue (and other state) into the class instance:
    If we went down the route of making them classes, it makes sense for this to be a modifier
    on the class definition itself, since it fundamentally alters the contract of the class, e.g.:

    ```swift
    class DataModel : SomeBaseClass, Actor { ... }
    actor class DataModel : SomeBaseActor { ... }
    ```

    This approach is interesting if and only if we value the ability to retroactively make a class into
    and actor. In my opinion, it seems that wrapping a class with a new actor is a more sensible
    way to solve this problem.


    #### Examples

    @@ -913,7 +912,7 @@ While this is a simple approach, there are two problems:
    before passing on the message:

    ```swift
    actor class Merge10Notifications {
    actor Merge10Notifications {
    var counter : Int = 0
    let otherActor = ... // set up by the init.
    actor func notify() {
    @@ -937,14 +936,12 @@ approach is to require all actors to face that complexity by baking it in as par
    model, reducing the number of choices a Swift programmer gets-to/has-to make. Both
    approaches have merit, but for the sake of this manifesto, we'll proceed with an opt-in model.

    The first thing you need is a way to opt in. As with actor syntax in general, there are three
    broad options: first-class actor syntax, a class declaration modifier or a protocol requirement,
    i.e., one of:
    The first thing you need is a way to opt in. As with actor syntax in general, there are two
    broad options: first-class actor syntax or a class declaration modifier, i.e., one of:

    ```swift
    reliable actor Notifier { ... }
    reliable actor class Notifier { ... }
    class Notifier : ReliableActor { ... }
    ```

    When one opts an actor into caring about reliability, a new requirement is imposed on all
    @@ -1040,13 +1037,12 @@ principles that guide it.
    One of these principles is the concept of [progressive disclosure of
    complexity](https://en.wikipedia.org/wiki/Progressive_disclosure): a Swift developer
    shouldn't have to worry about IPC or distributed compute if they don't care about it. This
    means that actors should opt-in to this, either through a new declaration modifier or through
    a protocol conformance, aligning with the ultimate design of the actor model itself, i.e., one of:
    means that actors should opt-in through a new declaration modifier, aligning with the ultimate
    design of the actor model itself, i.e., one of:

    ```swift
    distributed actor MyDistributedCache { ... }
    distributed actor class MyDistributedCache { ... }
    class MyDistributedCache : DistributedActor { ... }
    ```

    Because it has done this, the actor is now subject to two additional requirements.
    @@ -1220,7 +1216,7 @@ func printer(c chan string) {
    ... is basically analogous to this proposed Swift code:

    ```swift
    actor class Printer {
    actor Printer {
    actor func print(message: String) {
    print(message)
    }
    @@ -1273,7 +1269,7 @@ func (w Worker) Stop() {
    This sort of thing is much more naturally expressed in our proposal model:

    ```swift
    actor class Worker {
    actor Worker {
    actor func do(job: Job) {
    // ...
    }
  27. @lattner lattner revised this gist Aug 16, 2017. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -6,11 +6,11 @@

    This document is published in the style of a "Swift evolution manifesto", outlining a long-term
    view of how to tackle a very large problem. It explores *one possible* approach to adding
    a first-class concurrency model to Swift, but it isn't prescriptive and is not intended as a
    recipe for "the" ultimate design in Swift. As the open source swift-evolution mailing list
    discusses and iterates on a path forward, we may end up with a completely different
    approach. As such, this is merely meant to serve as a starting point for the discussion,
    helping to provide some structure.
    a first-class concurrency model to Swift, in an effort to catalyze positive discussion that leads
    us to a final best-possible design. As such, it isn't an approved or finalized design
    prescriptive of what Swift will end up adopting. It is the job of public debate on the open
    source swift-evolution mailing list to discuss and iterate towards that ultimate answer, and
    we may end up with a completely different approach.

    We focus on task-based concurrency abstractions commonly encountered in client
    and server applications, particularly those that are highly event driven (e.g. responding
  28. @lattner lattner revised this gist Aug 16, 2017. 1 changed file with 22 additions and 12 deletions.
    34 changes: 22 additions & 12 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,16 @@
    # Concurrency Manifesto
    # Concurrency in Swift: One possible approach

    * Author: [Chris Lattner](https://github.com/lattner)

    ## Introduction

    This document is published in the style of a "Swift evolution manifesto", outlining a long-term
    view of how to tackle a very large problem. It explores *one possible* approach to adding
    a first-class concurrency model to Swift, but has not (yet?) been adopted as the
    "plan" for future Swift versions.
    a first-class concurrency model to Swift, but it isn't prescriptive and is not intended as a
    recipe for "the" ultimate design in Swift. As the open source swift-evolution mailing list
    discusses and iterates on a path forward, we may end up with a completely different
    approach. As such, this is merely meant to serve as a starting point for the discussion,
    helping to provide some structure.

    We focus on task-based concurrency abstractions commonly encountered in client
    and server applications, particularly those that are highly event driven (e.g. responding
    @@ -934,10 +937,12 @@ approach is to require all actors to face that complexity by baking it in as par
    model, reducing the number of choices a Swift programmer gets-to/has-to make. Both
    approaches have merit, but for the sake of this manifesto, we'll proceed with an opt-in model.

    The first thing you need is a way to opt in. As with actor syntax in general, there are two
    broad options: this can either be a decl modifier or a protocol requirement, i.e., one of:
    The first thing you need is a way to opt in. As with actor syntax in general, there are three
    broad options: first-class actor syntax, a class declaration modifier or a protocol requirement,
    i.e., one of:

    ```swift
    reliable actor Notifier { ... }
    reliable actor class Notifier { ... }
    class Notifier : ReliableActor { ... }
    ```
    @@ -1011,17 +1016,17 @@ in the older Objective-C "[Distributed
    Objects](https://www.mikeash.com/pyblog/friday-qa-2009-02-20-the-good-and-bad-of-distributed-objects.html)" system)
    leads to serious problems:

    - Clients and servers are often written by different entities, which means that APIs must be
    able to evolve independently. Swift is already great at this.
    - Networks introduce new failure modes that the original API almost certainly did not
    anticipate.
    anticipate. This is covered by "reliable actors" described above.
    - Data in messages must be known-to-be `Codable`.
    - Clients and servers are often written by different entities, which means that APIs must be
    able to evolve independently.
    - Latency is much higher to remote systems, which can impact API design because
    too-fine-grained APIs perform poorly.

    In order to align with the goals of Swift, we cannot sweep these issues under the rug: we
    want to make the development process fast, but "getting something up and running" isn't the
    goal: it really needs to work - even in the failure cases. There is good news though,
    "Part 3 - Reliability" described a solution to the first point, and Swift already has great
    support for long-term API evolution.
    goal: it really needs to work - even in the failure cases.

    ### Design sketch for interprocess and distributed compute

    @@ -1036,9 +1041,10 @@ One of these principles is the concept of [progressive disclosure of
    complexity](https://en.wikipedia.org/wiki/Progressive_disclosure): a Swift developer
    shouldn't have to worry about IPC or distributed compute if they don't care about it. This
    means that actors should opt-in to this, either through a new declaration modifier or through
    a protocol conformance, aligning with the ultimate design of the actor model itself:
    a protocol conformance, aligning with the ultimate design of the actor model itself, i.e., one of:

    ```swift
    distributed actor MyDistributedCache { ... }
    distributed actor class MyDistributedCache { ... }
    class MyDistributedCache : DistributedActor { ... }
    ```
    @@ -1050,6 +1056,10 @@ Because it has done this, the actor is now subject to two additional requirement
    value returning `actor` methods must throw, for example.
    - Arguments and results of `actor` methods must conform to `Codable`.

    In addition, the author of the actor should consider whether the `actor` methods make
    sense in a distributed setting, given the increased latency that may be faced. Using coarse
    grain APIs could be a significant performance win.

    With this done, the developer can write their actor like normal: no change of language or
    tools, no change of APIs, no massive new conceptual shifts. This is true regardless of
    whether you're talking to a cloud service endpoint over JSON or an optimized API using
  29. @lattner lattner revised this gist Aug 16, 2017. 1 changed file with 32 additions and 32 deletions.
    64 changes: 32 additions & 32 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,7 @@ concurrency story in Swift along these lines:
    hundreds of thousands of tasks that are active at a time (e.g. one for every
    active client of the server).
    - Performance: As a stretch goal, it would be great to improve performance,
    e.g. by reducing the number of syncronization operations performed, and
    e.g. by reducing the number of synchronization operations performed, and
    perhaps even reducing the need for atomic accesses on many ARC operations.
    The compiler should be aided by knowing how and where data can cross task
    boundaries.
    @@ -84,10 +84,10 @@ it.

    It is clear that the multicore world isn't the future: it is the present! As such, it is
    essential for Swift to make it straight-forward for programmers to take
    advantage of hardware that is already prevalant in the world. At the same time,
    advantage of hardware that is already prevalent in the world. At the same time,
    it is already possible to write concurrent programs: since adding a concurrency model
    will make Swift more complicated, we need a strong justification for that complexity.
    To show opportunity for improvement, lets explore some of the pain that Swift
    To show opportunity for improvement, let's explore some of the pain that Swift
    developers face with the current approaches. Here we focus on GCD since almost
    all Swift programmers use it.

    @@ -111,7 +111,7 @@ func makeSandwich1(completionBlock: (result: Sandwich) -> Void) {
    }
    ```

    Error handling is particularly ugly, because the natural error handling mechanic in Swift cannot be used. You end up with code like this:
    Error handling is particularly ugly, because Swift's natural error handling mechanism cannot be used. You end up with code like this:

    ```swift
    func makeSandwich2(completionBlock: (result: Sandwich?, error: Error?) -> Void) {
    @@ -143,7 +143,7 @@ func makeSandwich2(completionBlock: (result: Sandwich?, error: Error?) -> Void)
    }
    ```

    Partially because asynchronous APIs are are onerous to use, there are many API defined in a synchronous form that can block (e.g. `UIImage(named: ...)`), and many of these APIs have no asynchronous alternative. Having a natural and canonical way to define and use these APIs will allow them to become pervasive. This is particularly important for new initiatives like the Swift on Server group.
    Partially because asynchronous APIs are onerous to use, there are many APIs defined in a synchronous form that can block (e.g. `UIImage(named: ...)`), and many of these APIs have no asynchronous alternative. Having a natural and canonical way to define and use these APIs will allow them to become pervasive. This is particularly important for new initiatives like the Swift on Server group.

    #### What queue am I on?

    @@ -207,13 +207,13 @@ Once an app is working, you then run into performance problems, because mutexes
    generally very inefficient - particularly when there are many cores and threads. Given decades
    of experience with this model, there are a number of attempts to solve certain corners of the
    problem, including
    [reader/writer locks](https://en.wikipedia.org/wiki/Readers–writer_lock),
    [double checked locking](https://en.wikipedia.org/wiki/Double-checked_locking), low-level
    [readers-writer locks](https://en.wikipedia.org/wiki/Readers–writer_lock),
    [double-checked locking](https://en.wikipedia.org/wiki/Double-checked_locking), low-level
    [atomic operations](https://en.wikipedia.org/wiki/Linearizability#Primitive_atomic_instructions)
    and advanced techniques like
    [read/copy/update](https://en.wikipedia.org/wiki/Read-copy-update). Each of these improves
    on mutexes in some respect, but the incredible complexity, unsafety, and fragility of the
    resultant model is itself a sign of a problem.
    resulting model is itself a sign of a problem.

    With all that said, shared mutable state is incredibly important when you're working at the
    level of systems programming: e.g. if you're *implementing* the GCD API or a kernel in Swift,
    @@ -302,7 +302,7 @@ This manifesto outlines several major steps to address these problems, which can
    incrementally to Swift over the span of years. The first step is quite concrete, but subsequent
    steps get increasingly vague: this is an early manifesto and there is more design work to
    be done. Note that the goal here is not to come up with inherently novel ideas, it is to pull
    together the best ideas from whereever we can get them, and synthesize those ideas into
    together the best ideas from wherever we can get them, and synthesize those ideas into
    something self-consistent that fits with the rest of Swift.

    The overarching observation here is that there are four major abstractions in computation
    @@ -336,7 +336,7 @@ introduction of a first-class [actor model](https://en.wikipedia.org/wiki/Actor_
    provides a way to define and reason about independent tasks who communicate between
    themselves with asynchronous message sending. The actor model has a deep history of
    strong academic work and was adopted and proven in
    [Erlang](http://www.erlang.org) and [Akka](http://akka.io), which successfully power a large
    [Erlang](https://www.erlang.org) and [Akka](http://akka.io), which successfully power a large
    number of highly scalable and reliable systems.
    With the actor model as a baseline, we believe we can achieve data isolation by ensuring that
    messages sent to actors do not lead to shared mutable state.
    @@ -364,7 +364,7 @@ No matter what global concurrency model is settled on for Swift, it is hard to i
    glaring problems we have dealing with asynchronous APIs. Asynchronicity is unavoidable
    when dealing with independently executing systems: e.g. anything involving I/O (disks,
    networks, etc), a server, or even other processes on the same system. It is typically "not ok"
    to block the current thread of execution just because something is taking awhile to load.
    to block the current thread of execution just because something is taking a while to load.
    Asynchronicity also comes up when dealing with multiple independent operations that can
    be performed in parallel on a multicore machine.

    @@ -435,8 +435,8 @@ More details are contained in the full proposal.
    ### New asynchronous APIs

    The introduction of async/await into the language is a great opportunity to introduce more
    asynchrous APIs to Cocoa and perhaps even entire new framework extensions (like a revised
    asynchrous file I/O API). The [Server APIs Project](https://swift.org/server-apis/) is also
    asynchronous APIs to Cocoa and perhaps even entire new framework extensions (like a revised
    asynchronous file I/O API). The [Server APIs Project](https://swift.org/server-apis/) is also
    actively working to define new Swift APIs, many of which are intrinsically asynchronous.


    @@ -465,7 +465,7 @@ concurrency primitives.
    Actors have a deep theoretical basis and have been explored by academia since the 1970s -
    the [wikipedia page on actors](https://en.wikipedia.org/wiki/Actor_model) and the
    [c2 wiki page](http://wiki.c2.com/?ActorsModel) are good places
    to start reading if you'd like to dive into some of the theoretic fundamentals that back the
    to start reading if you'd like to dive into some of the theoretical fundamentals that back the
    model. A challenge of this work (for Swift's purposes) is that academia assumes a pure actor
    model ("everything is an actor"), and assumes a model of communication so limited that it
    may not be acceptable for Swift. I'll provide a broad stroke summary of the advantages of
    @@ -484,7 +484,7 @@ Because these messages are unidirectional, there is no waiting, and thus deadloc
    impossible. In the academic model, all data sent in these messages is deep copied, which
    means that there is no data sharing possible between actors. Because actors cannot touch
    each other's state (and have no access to global state), there is no need for any
    syncronization constructs, eliminating all of the problems with shared mutable state.
    synchronization constructs, eliminating all of the problems with shared mutable state.

    To make this work pragmatically in the context of Swift, we need to solve several problems:

    @@ -693,16 +693,16 @@ an existence proof for an answer:
    always provide the semantics we need.
    - Teach the compiler to synthesize conformance for structs and enums whose members are
    all `ValueSemantical`, just like we do for `Codable`.
    - The compiler just checks for conformance to the `ValueSemantical` protocol and
    rejects any arguments and return values that do not conform.
    - The compiler just checks for conformance to the `ValueSemantical` protocol and
    rejects any arguments and return values that do not conform.

    The reiterate, the name `ValueSemantical` really isn't the right name for this: things like
    `UnsafePointer`, for example, shouldn't conform. Enumerating the possible options and
    evaluating the naming tradeoffs between them is a project for another day though.

    It is important to realize that this design does *not guarantee memory safety*. Someone
    could implement the protocol in the wrong way (thus lying about satisfying the requirements)
    and shared mutable state could occur. In the authors opinion, this is the right tradeoff:
    and shared mutable state could occur. In the author's opinion, this is the right tradeoff:
    solving this would require introducing onerous type system mechanics (e.g. something like
    the capabilities system in the [Pony](https://www.ponylang.org/) language). Swift already
    provides a model where memory safe APIs (e.g. `Array`) are implemented in terms of memory
    @@ -738,7 +738,7 @@ actor's state. That said, there is at least one important exception that we sho
    out: it is safe to pass a closure *literal* when it is known that it only closes over
    data by copy: using the same `ValueSemantical` copy semantics described above.

    This happens to be an extreme useful carveout, because it permits some interesting "callback"
    This happens to be an extremely useful carveout, because it permits some interesting "callback"
    abstractions to be naturally expressed without tight coupling between actors. Here is a silly
    example:

    @@ -767,7 +767,7 @@ actor Foo {
    }
    ```

    There is no practical way to know whether 'calculate' is thread safe or not. The only solution
    There is no practical way to know whether 'calculate' is thread-safe or not. The only solution
    is to scatter tons of annotations everywhere, including in headers for C code. I think that
    would be a non-starter.

    @@ -870,7 +870,7 @@ preferable to detect and report a programmer error as quickly as possible, rathe
    perhaps static analysis technology in the future), the goal is to make bugs shallow, and provide
    good stack traces and other information when they occur. This encourages them to be found
    and fixed quickly early in the development cycle. However, when the app ships, this
    philosophy is only great all the bugs were actually found, because an undetected problem
    philosophy is only great if all the bugs were actually found, because an undetected problem
    causes the app to suddenly terminate itself.

    Sudden termination of a process is hugely problematic if it jeopardizes user data, or - in the
    @@ -953,8 +953,8 @@ other systems, but I imagine two potential solutions:
    reasoning about how to process and respond to those failures. An actor's `init()` could
    then use this API to register its failure handler the system.
    2) Force *all* `actor` methods to throw, with the semantics that they only throw if the actor
    has crashed. This forces clients of the reliable actor to handle a potential crash, and do so
    on the granularity of all messages sent to that actor.
    has crashed. This forces clients of the reliable actor to handle a potential crash, and do so
    on the granularity of all messages sent to that actor.

    Between the two, the first approach is more appealing to me, because it allows factoring
    out the common failure logic in one place, rather than having every caller have to write (hard
    @@ -1120,22 +1120,22 @@ take one step at a time, ensuring that each is as good as we can make it.

    When designing a concurrency system for Swift, we should look at the designs of other
    languages to learn from them and ensure we have the best possible system. There are
    thousands of different programming langauges, but most have very small communities, which
    thousands of different programming languages, but most have very small communities, which
    makes it hard to draw practical lessons out from those communities. Here we look at a few
    different systems, focusing on how their concurrency design works, ignoring syntactic and
    other unrelated aspects of their design.

    ### Pony

    Perhaps the most relevant active research language is the [Pony programming
    language](https://www.ponylang.org). It is actor based and uses them and other techniques
    to provide a type-safe, memory safe, deadlock-free, and datarace-free programming model.
    language](https://www.ponylang.org). It is actor-based and uses them along with other techniques
    to provide a type-safe, memory-safe, deadlock-free, and datarace-free programming model.
    The biggest
    semantic difference between the Pony design and the Swift design is that Pony invests a
    lot of design complexity into providing [capability-based
    security](https://en.wikipedia.org/wiki/Capability-based_security), which impose a high
    learning curve. In contrast, the model proposed here builds on Swift's mature system of
    value semantics. If transfering object graphs between actors (in a guaranteed memory safe
    value semantics. If transferring object graphs between actors (in a guaranteed memory safe
    way) becomes important in the future, we can investigate expanding the [Swift Ownership
    Model](https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md) to
    cover more of these use-cases.
    @@ -1144,11 +1144,11 @@ cover more of these use-cases.
    ### Akka Actors in Scala

    [Akka](http://akka.io) is a framework written in the [Scala programming
    language](http://www.scala-lang.org), whose mission is to "Build powerful reactive,
    language](https://www.scala-lang.org), whose mission is to "Build powerful reactive,
    concurrent, and distributed applications more easily". The key to this is their well developed
    [Akka actor system](http://doc.akka.io/docs/akka/current/scala/actors.html), which is the
    principle abstraction that developers use to realize these goals (and it, in turn, was heavily
    influenced by [Erlang](http://www.erlang.org). One of the great things about
    influenced by [Erlang](https://www.erlang.org). One of the great things about
    Akka is that it is mature and widely used by a lot of different organizations and people. This
    means we can learn from its design, from the design patterns the community has explored,
    and from experience reports describing how well it works in practice.
    @@ -1282,8 +1282,8 @@ communication patterns. Synchronous messages to a channel can only be completel
    if there is something listening and waiting for them, which can lead to performance
    advantages (and some disadvantages). Go doesn't
    attempt to provide any sort of memory safety or data isolation, so goroutines have the
    usual assortment of mutexs and other APIs to use, and are subject to standard bugs like
    deadlock and [data races](http://accelazh.github.io/go/Goroutine-Can-Race). Races can
    usual assortment of mutexes and other APIs to use, and are subject to standard bugs like
    deadlocks and [data races](http://accelazh.github.io/go/Goroutine-Can-Race). Races can
    even break [memory safety](https://research.swtch.com/gorace).

    I think that the most important thing the Swift community can learn from Go's concurrency
    @@ -1316,7 +1316,7 @@ but not as helpful for higher levels), and they don't provide much guidance for
    about which abstractions to choose, how to structure an application, etc. Rust also doesn't
    provide an obvious model to scale into distributed applications.

    That said, improving syncronization for Swift systems programmers will be a goal once the
    That said, improving synchronization for Swift systems programmers will be a goal once the
    basics of the [Swift Ownership
    Model](https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md) come
    together. When that happens, it makes sense to take another look at the Rust abstractions
  30. @lattner lattner revised this gist Aug 16, 2017. 1 changed file with 86 additions and 66 deletions.
    152 changes: 86 additions & 66 deletions TaskConcurrencyManifesto.md
    Original file line number Diff line number Diff line change
    @@ -4,13 +4,17 @@

    ## Introduction

    This document explores one possible approach to adding a first-class concurrency model
    to Swift. We focus on task-based concurrency abstractions commonly encountered in client
    This document is published in the style of a "Swift evolution manifesto", outlining a long-term
    view of how to tackle a very large problem. It explores *one possible* approach to adding
    a first-class concurrency model to Swift, but has not (yet?) been adopted as the
    "plan" for future Swift versions.

    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 coherent design thread that can be built over the span of years to
    Instead, it outlines a single coherent design thread that can be built over the span of years to
    incrementally drive Swift to further greatness.

    ### Concurrency in Swift 1...4
    @@ -55,15 +59,15 @@ concurrency story in Swift along these lines:
    data structure.
    - Safety: Swift's current model provides no help for race conditions, deadlock
    and other concurrency problems. Completion handlers can get called on a
    surprising queue. These issues should be improved, and ideally we would get
    surprising queue. These issues should be improved, and we would like to get
    to a "safe by default" programming model.
    - Scalability: Particularly in server applications, it is desirable to have
    hundreds of thousands of tasks that are active at a time (e.g. one for every
    active client of the server).
    - Performance: As a stretch goal, it would be great to improve performance,
    e.g. by reducing the number of syncronization operations performed, and
    perhaps even reducing the need for atomic accesses on many ARC operations.
    The compiler should be aided by knowing how and where data can cross thread
    The compiler should be aided by knowing how and where data can cross task
    boundaries.
    - Excellence: More abstractly, we should look to the concurrency models
    provided by other languages and frameworks, and draw together the best ideas
    @@ -78,13 +82,13 @@ it.

    ### Why a first class concurrency model?

    It is clear that the multicore world isn't the future: it is the present - it is
    It is clear that the multicore world isn't the future: it is the present! As such, it is
    essential for Swift to make it straight-forward for programmers to take
    advantage of hardware that is already prevalant in the world. At the same time,
    it is already possible to write concurrent programs: since adding a concurrency model
    will make Swift more complicated, we need a strong justification for that complexity.
    To show opportunity for improvement, lets explore some of the pain that Swift
    developers face with the current approach. Here we focus on GCD since almost
    developers face with the current approaches. Here we focus on GCD since almost
    all Swift programmers use it.

    #### Asynchronous APIs are difficult to work with
    @@ -182,7 +186,7 @@ build tools to debug, profile, and reason about what is going wrong, etc.
    Lets define "Shared mutable state" first: "state" is simply data used by the program. "Shared"
    means the data is shared across multiple tasks (threads, queues, or whatever other concurrency
    abstraction is used). State shared by itself is not harmful: so long as no-one is modifying the
    data, there is no problem with have multiple readers of that data.
    data, it is no problem having multiple readers of that data.

    The concern is when the shared data is mutable, and therefore someone is changing it while
    others tasks are looking at it. This opens an enormous can of worms that the software world has been
    @@ -200,15 +204,15 @@ problems. There have been a number of attempts to improve this situation, notab
    thing improves the syntactic side of the equation but doesn't fix the underlying problem.

    Once an app is working, you then run into performance problems, because mutexes are
    generally very inefficient, particularly when there are many cores and threads. Given decades
    generally very inefficient - particularly when there are many cores and threads. Given decades
    of experience with this model, there are a number of attempts to solve certain corners of the
    problem, including
    [reader/writer locks](https://en.wikipedia.org/wiki/Readers–writer_lock),
    [double checked locking](https://en.wikipedia.org/wiki/Double-checked_locking), low-level
    [atomic operations](https://en.wikipedia.org/wiki/Linearizability#Primitive_atomic_instructions)
    and advanced techniques like
    [read/copy/update](https://en.wikipedia.org/wiki/Read-copy-update). Each of these improves
    on mutexes in some aspect, but the incredible complexity, unsafety, and fragility of the
    on mutexes in some respect, but the incredible complexity, unsafety, and fragility of the
    resultant model is itself a sign of a problem.

    With all that said, shared mutable state is incredibly important when you're working at the
    @@ -221,7 +225,7 @@ focus of this proposal.
    I encourage anyone interested in this space to read [Is
    Parallel Programming Hard, And, If So, What Can You Do About
    It?](https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html). It is
    a great survey developed by Paul E McKenney who has
    a great survey developed by Paul E. McKenney who has
    been driving forward efforts to get the Linux kernel to scale to massively multicore
    machines (hundreds of cores). Besides being an impressive summary of hardware characteristics
    and software synchronization approaches, it also shows the massive complexity creep that
    @@ -244,26 +248,29 @@ mutations to the cache line have to be pushed out to other cores that are simply

    This has a number of other knock on effects: processors have quickly moved to having
    [relaxed consistency models](https://en.wikipedia.org/wiki/Consistency_model) which make
    shared memory programming more complicated. Atomic accesses (and other concurrency
    related primitives like compare/exchange) are now 20-100x slower than non-atomic
    accesses. These costs and problems continue to scale with core count, yet today it isn't
    atypical to have large machines with dozens or hundreds of cores.
    shared memory programming even more complicated. Atomic accesses (and other
    concurrency-related primitives like compare/exchange) are now 20-100x slower than non-atomic
    accesses. These costs and problems continue to scale with core count, yet it
    isn't hard to find a large machine with dozens or hundreds of cores today.

    The recent breakthroughs in hardware performance have come from hardware that has
    dropped the goal of having shared memory. Notably,
    If you look at the recent breakthroughs in hardware performance, they have come from
    hardware that has dropped the goal of shared memory. Notably,
    [GPUs](https://en.wikipedia.org/wiki/Graphics_processing_unit) have been extremely
    successful at scaling to extremely high core counts, notably because they expose a
    programming model that encourages the use of fast local memory instead of shared global
    memory.
    memory. Supercomputers frequently use [MPI](https://en.wikipedia.org/wiki/Message_Passing_Interface)
    for explicitly managed memory transfers, etc. If you explore this from first principles, the
    speed of light and wire delay become an inherently limiting factor for very large shared
    memory systems.

    The point of all of this is that it is highly desirable for Swift to move in a direction where Swift
    programs run great on large-scale multi-core machines, and hopefully unblock the next step
    in hardware evolution.
    programs run great on large-scale multi-core machines. With any luck, this could unblock the
    next step in hardware evolution.

    #### Shared mutable state doesn't scale beyond a single process

    It's somewhat tautological, but a model built on shared mutable state doesn't work if you
    don't have shared memory.
    Ok, it is somewhat tautological, but any model built on shared mutable state doesn't work
    in the absence of shared memory.

    Because of this, the software industry has a complexity explosion of systems for [interprocess
    communication](https://en.wikipedia.org/wiki/Inter-process_communication): things like
    @@ -276,23 +283,24 @@ computation](https://en.wikipedia.org/wiki/Distributed_computing)
    and cloud APIs then reimplement the same abstractions in yet-another way, because
    shared memory is impractical in that setting.

    The observation that I want to make here is simply that this is a really unfortunate state of
    affairs. A better world would be for application developers to have an abstraction where they
    can build their data abstractions, concurrency abstractions, and reason about their
    The key observation here is simply that this is a really unfortunate state of
    affairs. A better world would be for app developers to have a way to
    build their data abstractions, concurrency abstractions, and reason about their
    application in the large, even if it is running across multiple machines in a cloud ecosystem.
    If you want your single process app to start running in an IPC or distributed setting, you
    should only have to teach your types how to serialize/🐟 themselves, deal with new
    errors that can arise, and configure where you want each bit of code to run. You shouldn't
    have to rewrite large parts of the application - using entirely new technology stacks.
    errors that can arise, then configure where you want each bit of code to run. You shouldn't
    have to rewrite large parts of the application - certainly not with an entirely new technology
    stack.

    After all, app developers don't design their API with JSON as the input and output format
    for each function, so why should cloud developers?

    ## Overall vision

    This manifesto outlines three major steps to address these problems, which can be added
    This manifesto outlines several major steps to address these problems, which can be added
    incrementally to Swift over the span of years. The first step is quite concrete, but subsequent
    steps get increasingly vague, because this is a manifesto, and there is more design work to
    steps get increasingly vague: this is an early manifesto and there is more design work to
    be done. Note that the goal here is not to come up with inherently novel ideas, it is to pull
    together the best ideas from whereever we can get them, and synthesize those ideas into
    something self-consistent that fits with the rest of Swift.
    @@ -305,8 +313,8 @@ that are interesting to build a model on top of:
    - message passing and data isolation
    - distributed data and compute

    Swift already has a fully developed model for the first point, incrementally refined and
    improved over the course of years, so we won't talk about it much. It is important to observe
    Swift already has a fully-developed model for the first point, incrementally refined and
    improved over the course of years, so we won't talk about it here. It is important to observe
    that the vast majority of low-level computation benefits from imperative control flow,
    [mutation with value semantics](https://developer.apple.com/videos/play/wwdc2015/414/),
    and yes, reference semantics with classes. These concepts are the important low-level
    @@ -319,8 +327,8 @@ independent operations. Fortunately, Swift is not the first language to face
    these challenges: the industry as a whole has fought this dragon and settled on
    [async/await](https://en.wikipedia.org/wiki/Await) as the right abstraction. We propose
    adopting this proven concept outright (with a Swift spin on the syntax). Adopting
    async/await will dramatically improve existing Swift code, without requiring the introduction
    of any new approaches to concurrency.
    async/await will dramatically improve existing Swift code, dovetailing with existing and
    future approaches to concurrency.

    The next step is to define a programmer abstraction to define and model the independent
    tasks in a program, as well as the data that is owned by those tasks. We propose the
    @@ -333,10 +341,10 @@ number of highly scalable and reliable systems.
    With the actor model as a baseline, we believe we can achieve data isolation by ensuring that
    messages sent to actors do not lead to shared mutable state.

    Speaking of reliable systems, introducing an actor model is a good opportunity and execuse
    Speaking of reliable systems, introducing an actor model is a good opportunity and excuse
    to introduce a mechanism for handling and partially recovering from runtime failures (like
    force-unwrap operations, array out of bounds, etc). There are several options that are
    possible to implement, we explore them and make a recommendation that we think will be a
    failed force-unwrap operations, out-of-bounds array accesses, etc). We explore several
    options that are possible to implement and make a recommendation that we think will be a
    good for for UI and server applications.

    The final step is to tackle whole system problems by enabling actors to run in different
    @@ -963,7 +971,7 @@ How well can the process clean up from the failure? Do we attempt to release me
    and other resources allocated by that actor? There are multiple possible designs, but I
    advocate for a design where **no cleanup is performed**: if an actor crashes, the runtime
    propagates that error to other actors and runs any recovery handlers (as described in the
    previous section) but that it *should not* attempt to clean up the resources owned by the
    previous section) but that it **should not** attempt to clean up the resources owned by the
    actor.

    There are a number of reasons for this, but the most important is that the failed actor just
    @@ -974,7 +982,7 @@ probable that the high-level invariants of various classes aren't intact, which
    safe to run the `deinit`-ializers for the classes.

    Beyond the semantic problems we face, there are also practical complexity and efficiency
    issues at stake: it takes code and metadata to be able to unwind the actor stack and release
    issues at stake: it takes code and metadata to be able to unwind the actor's stack and release
    active resources. This code and metadata takes space in the application, and it also takes
    time at compile time to generate it. As such, the choice to provide a model that attempted
    to recover from these
    @@ -992,13 +1000,15 @@ As described in the motivation section, a single application process runs in the
    larger system: one that often involves multiple processes (e.g. an app and an XPC daemon)
    communicating through [IPC](https://www.mikeash.com/pyblog/friday-qa-2009-01-16.html),
    clients and servers communicating through networks, and
    servers communicating with each other in "[the cloud](https://tr4.cbsistatic.com/hub/i/r/2016/11/29/9ea5f375-d0dd-4941-891b-f35e7580ae27/resize/770x/982bcf36f7a68242dce422f54f8d445c/49nocloud.jpg)". The points
    servers communicating with each other in "[the cloud](https://tr4.cbsistatic.com/hub/i/r/2016/11/29/9ea5f375-d0dd-4941-891b-f35e7580ae27/resize/770x/982bcf36f7a68242dce422f54f8d445c/49nocloud.jpg)" (using
    JSON, protobufs, GRPC, etc...). The points
    of similarity across all of these are that they mostly consist of independent tasks that
    communicate with each other by sending structured data using asynchronous message
    sends, and that they cannot practically share mutable state. This is starting to sound familiar.

    That said, there are differences as well, and attempting to papering over them (as was done
    in the older "[Distributed Objects](https://www.mikeash.com/pyblog/friday-qa-2009-02-20-the-good-and-bad-of-distributed-objects.html)" system)
    in the older Objective-C "[Distributed
    Objects](https://www.mikeash.com/pyblog/friday-qa-2009-02-20-the-good-and-bad-of-distributed-objects.html)" system)
    leads to serious problems:

    - Networks introduce new failure modes that the original API almost certainly did not
    @@ -1009,16 +1019,18 @@ leads to serious problems:

    In order to align with the goals of Swift, we cannot sweep these issues under the rug: we
    want to make the development process fast, but "getting something up and running" isn't the
    goal: it really needs to work - even in the failure cases.
    goal: it really needs to work - even in the failure cases. There is good news though,
    "Part 3 - Reliability" described a solution to the first point, and Swift already has great
    support for long-term API evolution.

    ### Design sketch for interprocess and distributed compute

    The actor model is a well-known solution to these problems, and has been deployed
    The actor model is a well-known solution in this space, and has been deployed
    successfully in less-mainstream languages like
    [Erlang](https://en.wikipedia.org/wiki/Erlang_(programming_language)#Concurrency_and_distribution_orientation).
    Bringing the ideas to Swift just requires that we make sure it fits cleanly into the existing
    system, taking advantage of the characteristics of Swift and ensuring that it stays true to the
    principles that guide its design.
    design, taking advantage of the characteristics of Swift and ensuring that it stays true to the
    principles that guide it.

    One of these principles is the concept of [progressive disclosure of
    complexity](https://en.wikipedia.org/wiki/Progressive_disclosure): a Swift developer
    @@ -1034,7 +1046,7 @@ a protocol conformance, aligning with the ultimate design of the actor model its
    Because it has done this, the actor is now subject to two additional requirements.

    - The actor must fulfill the requirements of a `reliable actor`, since a
    `distributed actor` is a further refinement of the reliability model. This means that all
    `distributed actor` is a further refinement of a reliable actor. This means that all
    value returning `actor` methods must throw, for example.
    - Arguments and results of `actor` methods must conform to `Codable`.

    @@ -1060,7 +1072,7 @@ it would be interesting to start building things like:

    - New APIs need to be built to start actors in interesting places: IPC contexts, cloud
    providers, etc. These APIs should be consistent with each other.
    - The underlying runtime needs to be built, which handles the serialization hand shaking,
    - The underlying runtime needs to be built, which handles the serialization, handshaking,
    distributed reference counting of actors, etc.
    - To optimize IPC communications with shared memory (mmaps), introduce a new protocol
    that refines `ValueSemantical`. Heavy weight types can then opt into using it where it
    @@ -1097,8 +1109,8 @@ tend to be more pragmatic (e.g. more efficient). The proposed model allows some
    interesting hybrid approaches, and allows subsystems to be moved "in process" of the main
    kernel when efficiency is needed, or pushed "out of process" when they are untrusted or
    when reliability is paramount, all without rewriting tons of code to achieve it. Swift's focus on
    stable APIs and API resilience also encourages and enables a split between kernel core and
    driver development.
    stable APIs and API resilience also encourages and enables a split between the core kernel
    and driver development.

    In any case, there is a lot of opportunity to make the software world better, but it is also a
    long path to carefully design and build each piece in a deliberate and intentional way. Let's
    @@ -1123,10 +1135,10 @@ semantic difference between the Pony design and the Swift design is that Pony in
    lot of design complexity into providing [capability-based
    security](https://en.wikipedia.org/wiki/Capability-based_security), which impose a high
    learning curve. In contrast, the model proposed here builds on Swift's mature system of
    value semantics. If transfering object graphs between actors becomes important in the
    future, we can investigate expanding the [Swift Ownership
    value semantics. If transfering object graphs between actors (in a guaranteed memory safe
    way) becomes important in the future, we can investigate expanding the [Swift Ownership
    Model](https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md) to
    cover similar use-cases.
    cover more of these use-cases.


    ### Akka Actors in Scala
    @@ -1139,7 +1151,7 @@ principle abstraction that developers use to realize these goals (and it, in tur
    influenced by [Erlang](http://www.erlang.org). One of the great things about
    Akka is that it is mature and widely used by a lot of different organizations and people. This
    means we can learn from its design, from the design patterns the community has explored,
    and from the experience reports out their describing how well it works in practice.
    and from experience reports describing how well it works in practice.

    The Akka design shares a lot of similarities to the design proposed here, because it is an
    implementation of the same actor model. It is built on futures, asynchronous message sends,
    @@ -1166,8 +1178,8 @@ including, for example:
    - Descriptions of the ease and benefits of [sharding servers written in Akka](http://michalplachta.com/2016/01/23/scalability-using-sharding-from-akka-cluster/)
    - Success reports from lots of folks.

    Further, there are surely a lot of members of the Swift community who have encountered the
    model, and they can share their experiences as well.
    Further, it is likely that some members of the Swift community have encountered this
    model, it would be great if they share their experiences, both positive and negative.

    ### Go

    @@ -1178,7 +1190,7 @@ the Go language, including simplicity and preference for programming with low le
    abstraction. I have no evidence that this is the case, but I speculate that this model was
    influenced by the domains that Go thrives in: the Go model of channels and communicating
    independent goroutines almost directly reflects how servers communicate over network
    connections.
    connections (including core operations like `select`).

    The proposed Swift design is higher abstraction than the Go model, but directly reflects one
    of the most common patterns seen in Go: a goroutine whose body is an infinite loop over a
    @@ -1195,19 +1207,19 @@ func printer(c chan string) {
    }
    ```

    ... is basically analogous to Swift code:
    ... is basically analogous to this proposed Swift code:

    ```swift
    actor class Printer {
    actor func doIt(message: String) {
    actor func print(message: String) {
    print(message)
    }
    }
    ```

    The Swift design is more declarative than the Go code, but doesn't show any advantages
    The Swift design is more declarative than the Go code, but doesn't show many advantages
    or disadvantages in something this small. However, with more realistic examples, the
    advantages of the higher level declarative approach show benefit. For example,
    advantages of the higher-level declarative approach show benefit. For example,
    it is common for goroutines to listen on multiple channels, one for each message they
    respond to. This example (borrowed from [this blog
    post](http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/)) is fairly
    @@ -1265,26 +1277,34 @@ actor class Worker {
    That said, there are advantages and other tradeoffs to the Go model as well. Go builds on
    [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes), which allows
    more adhoc structures of communication. For example, because
    goroutines can listen to multiple channels, and because multiple goroutines can send to a
    single channel it is easier to set up some (advanced) communication patterns. Syncronous
    messages to a channel can only be completely sent if there is something listening and
    waiting for them, which can lead to performance advantages and disadvantages. Go doesn't
    goroutines can listen to multiple channels it is occasionally easier to set up some (advanced)
    communication patterns. Synchronous messages to a channel can only be completely sent
    if there is something listening and waiting for them, which can lead to performance
    advantages (and some disadvantages). Go doesn't
    attempt to provide any sort of memory safety or data isolation, so goroutines have the
    usual assortment of mutexs and other APIs to use, and are subject to standard bugs like
    deadlock and [data races](http://accelazh.github.io/go/Goroutine-Can-Race).
    deadlock and [data races](http://accelazh.github.io/go/Goroutine-Can-Race). Races can
    even break [memory safety](https://research.swtch.com/gorace).

    I think that the most important thing the Swift community can learn from Go's concurrency
    model is the huge benefit that comes from a highly scalable runtime model. It is common to
    have hundreds of thousands or even a million goroutines running around in a server. The
    ability to stop worrying about "running out of threads" is huge, and is one of the key decisions
    that contributed to the rise of Go in the cloud.

    The other lesson is that (while it is important to have a "best default" solution to reach for in
    the world of concurrency) we shouldn't overly restrict the patterns that developers are allowed
    to express. This is a key reason why the async/await design is independent of futures or any
    other abstraction. A channel library in Swift will be as efficient as the one in Go, and if shared
    mutable state and channels are the best solution to some specific problem, then we should
    embrace that fact, not hide from it. That said, I expect these cases to be very rare :-)

    ### Rust

    Rust's approach to concurrency builds on the strengths of its ownership system to allow
    library-based concurrency patterns to be built on top. They support message passing
    library-based concurrency patterns to be built on top. Rust supports message passing
    (through channels), but also support locks and other typical abstractions for shared mutable
    state. Rust's approaches are well suited for systems programmers which are the primary
    state. Rust's approaches are well suited for systems programmers, which are the primary
    target audience of Rust.

    On the positive side, the Rust design provides a lot of flexibility, a wide range of different