[Pitch] Synthesizing Concurrency: A Pitch For High-Level Abstractions & Low-Level Intelligence

Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call

···

+---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

Sorry I don't get the code. In particular:

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Doesn't make sense `async`'s closure doesn't return anything.

What am I missing?

  -- Howard.

···

On 17 November 2017 at 10:50, Christopher Heath via swift-evolution < swift-evolution@swift.org> wrote:

Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless
of concurrency implementation (however current proposal uses GCD examples
for design), concurrency can be synthesized by the compiler and remove many
lines of boilerplate code. Offering benefits to Application, Server and OS
Developers alike; with easy and intelligent concurrency conformance. Also,
should the community decide to head in another direction with concurrency
this should be a relatively mappable idea to any Synchronization Primitive
with a little work.

Thanks for looking, and I hope you like and want to contribute to the
discussion of the Synthesizing Concurrency proposal. I’ve added a printout
below. Please give it a read or check out the gist:
NNNN-synthesize-concurrency.md · GitHub

   - Chris

Printout :
*Synthesizing Concurrency*

   - Proposal: SE-NNNN
   <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
   - Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
   - Review Manager: TBD
   - Status: *Pending Discussion*
   - Implementation: *Awaiting Implementation*
   - Decision Notes: TBD

*Introduction*
Developers have to write large amounts of boilerplate code to support
concurrency in complex types. This proposal offers a way for the compiler
to automatically synthesize conformance to a high-level Concurrent protocol
to reduce concurrent boilerplate code, in a set of scenarios where
generating the correct implementation is known to be possible.
Specifically:

   - It aims to provide a high-level Swift protocol that offers opt-in
   concurrency support for any conformable type
   - It aims to provide a well-defined set of thread-safe, concurrent
   implementations for types, their properties, and methods.
   - It aims to provide a language/library compatible implementation with
   deadlock prevention.

*Motivation*
Building robust types in Swift can involve writing significant boilerplate
code to support concurrency. By eliminating the complexity for the users,
we make Concurrent types much more appealing to users and allow them to use
their own types in optimized concurrent and parallel environments that
require thread safety with no added effort on their part (beyond declaring
the conformance).
Concurrency is typically not pervasive across many types, and for each one
users must implement the concurrent code such that it performs some form of
synchronization to prevent unexpected behavior.

*Note: Due to it's current status in Swift and use in the **Runtime*
<swift/Once.cpp at main · apple/swift · GitHub*,
examples are written in **Grand Central Dispatch*
<https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or
changed, they must each have their own concurrency code and since it must
be manually written, it's possible to get it wrong, either by omission or
typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type
that implements concurrency to do so without introducing bottlenecks or
different forms of synchronization for some functions and not others, this
leads to illegible and inefficient code that may defeat the purpose of
implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and
inconvenient to write.
Swift already derives conformance to a number of protocols, automatically
synthesizing their inner-workings when possible. Since there is precedent
for synthesized conformances in Swift, we propose extending it to
concurrency in predictable circumstances.

*Proposed solution*
In general, we propose that a type synthesize conformance to Concurrent as
long as the compiler has reasonable insight into the type. We describe the
specific conditions under which these conformances are synthesized below,
followed by the details of how the conformance requirements are implemented.

*Requesting synthesis is opt-in*
Users must *opt-in* to automatic synthesis by declaring their type as
Concurrent without implementing any of its requirements. This conformance
must be part of the *original type declaration* and not on an extension
(see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below
will cause the compiler to synthesize an implementation of an internalQueue
and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an
explicit declaration—provides a number of benefits:

   - The syntax for opting in is natural; there is no clear analogue in
   Swift today for having a type opt out of a feature.
   - It requires users to make a conscious decision about the public API
   surfaced by their types. Types cannot accidentally "fall into" conformances
   that the user does not wish them to; a type that does not initially support
   Concurrent can be made to at a later date, but the reverse is a potentially
   breaking change.
   - The conformances supported by a type can be clearly seen by
   examining its source code; nothing is hidden from the user.
   - We reduce the work done by the compiler and the amount of code
   generated by not synthesizing conformances that are not desired and not
   used.
   - As will be discussed later, explicit conformance significantly
   simplifies the implementation for recursive types.

*Overriding synthesized conformances*
Any user-provided implementations of an internalQueue and use of async or
sync will override the default implementations that would be provided by
the compiler.

*Defining conditions where synthesis is allowed*
For example take the struct below, which contains all-kinds of properties;
variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

*Synthesized Requirements*

*Constant Properties*

   - Constants are *always* accessed asynchronously.

A Constant is guaranteed to be immutable and therefore able to be read
from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this
implementation, adding an asynchronous access point to any Constant on a
Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

*Synthesized requirements for Variable Properties*

   - Variables are *always* accessed synchronously.

A Variable is mutable and therefore each thread must schedule writes and
reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a
value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any
Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has
finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in
order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

*Synthesized requirements for Computed Properties*

   - Computed Properties are *always* accessed synchronously.

A Computed Property is essentially a function that gets called to create a
value from other values. These other values can be mutable and therefore
each thread must schedule writes and reads separately out of concern for
possible mutation. (Note: If a computed property only accesses Constants,
it should probably be a one-time set Constant; Swift
<https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any
Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

*Considerations for recursive types and abstraction*
By making the synthesized conformances opt-in, recursive types have their
requirements fall into place with no extra effort. In any cycle belonging
to a recursive type, every type in that cycle must declare its conformance
explicitly. If a type does so but cannot have its conformance synthesized
because it does not satisfy the conditions above, then it is simply an
error for *that* type and not something that must be detected earlier by
the compiler in order to reason about *all* the other types involved in
the cycle. (On the other hand, if conformance were implicit, the compiler
would have to fully traverse the entire cycle to determine eligibility,
which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or
property can access another synchronous function or property, introduces a
problem: Deadlocking.

*The Deadlock Problem*
Or just Deadlocking, is a problem where a complex program cannot continue
execution because one or more threads is waiting on a resource to become
available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous
function or property; this is defined as a Deadlock, because the first
cannot finish without the second being run and the second cannot execute
without the first being finished.

*Solving the Deadlock Problem*
In complex functions where any number of synchronous and asynchronous
calls can happen inside a larger scope it is required that the compiler
know how to handle compilation of such functions, that may access many
concurrent objects through a multitude of calls. Much like Automatic
Reference Counting
<https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments
and decrements a counter to determine whether an object should be marked
for deallocation, we suggest that during compilation a call or set of calls
is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync

    async() // 1 Async

    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync

    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would
today, and wrap each usage in-scope with an asynchronous or synchronous
requirement.
Specifically:

   - If a higher-level function accesses only asynchronous functions or
   properties internally, that function can be executed in-order as a single
   asynchronous call and inlining access to all non-modified calls.
   - The same is true of synchronous functions or properties. They can be
   executed in-order as a single synchronous call and inlining access to
   existing non-modified calls.
   - If at any point a function or property, accesses an asynchronous and
   synchronous call then that function must be run as a single synchronous
   call.

*Implementation details*
Deadlock Prevention is then inherent by synthesis. The following example
explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int
arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int
arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();

    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int
arg0)

    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_
AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18,
__NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_
AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_
AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 &
0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5async
ySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFla
gsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0)
{ // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();

    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int
arg0)

    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any
safety, like a non-concurrent type. As well as two more which call that
function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and
places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but
instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead
of rehashing lets look at the more interesting complex case. We start with
this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call,
since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-----------------------------------------------------------
--------------------------+
    > Combination
                >
    > +---------------------------------------+
+---------------------------------------+ |
    > > TwoAsyncs | |
AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+
+-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | |
SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+
+-------------+ | |
    > +---------------------------------------+
+---------------------------------------+ |
    +-----------------------------------------------------------
--------------------------+
Becomes:
    +-----------------------------------------------------------
--------------------------+
    > Combination //Sync
                >
    > +---------------------------------------+
+---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination
//Sync | |
    > > +-------------+ +-------------+ | | +-------------+
+-------------+ | |
    > > > Standard | | Standard | | | | Standard | |
Standard | | |
    > > +-------------+ +-------------+ | | +-------------+
+-------------+ | |
    > +---------------------------------------+
+---------------------------------------+ |
    +-----------------------------------------------------------
--------------------------+

*We've already made great decisions about thread-safety by implementing *
*SE-0035*
<https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt;\*
for Value Types*
SE-0035 Limiting Inout Capture
<https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt;
actually provides us with a proof-of-concept as to why Value Types should
not be asynchronously mutated inside a closure.

*Source compatibility*
By making the conformance opt-in, this is a purely additive change that
should not affect existing code and should be easily applicable to stdlib
types.
Some current types using Grand Central Dispatch
<https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited
for recursive-implementation, if a user wishes to replace their own
implementation with this synthesized one.

*Effect on ABI stability*
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on
this.)

*Effect on API resilience*
N/A.

*Alternatives considered*
In order to realistically scope this proposal, we considered but
ultimately deferred the following items, some of which could be proposed
additively in the future.

*Synthesis in extensions*
Requirements will be synthesized only for protocol conformances that are *part
of the type declaration itself;* conformances added in extensions will
not be synthesized.
However, to align with Codable in the context of SR-4920
<Issues · apple/swift-issues · GitHub, we will also currently forbid
synthesized requirements in extensions in the same file; this specific case
can be revisited later for all derived conformances.

*Explicit Manglings*
Because accesses are compiled and their async or sync wrappers are
deterministic from use case, it may be useful to create specific Manglings;
this is *optional*.

*Embedding or Building Dispatch*
Dispatch already provides us with a very powerful and exacting standard
for concurrency in Swift, it would be even more useful if embedded directly
in the runtime with replacements like that currently in the Runtime
<swift/Once.cpp at main · apple/swift · GitHub;
.
I feel as if most of the reason this would be frowned upon is a Swift
desire for style, code cleanliness and some hope of a 'better' (whatever
that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand
Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as
a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

*Keyword Overrides*
It is worth mentioning a Keyword could be used for overriding a function
and defining explicit behavior as sync or async. However, this opens the
door to misuse and incorrect code that can only be debugged at runtime with
TSAN. And while we love TSAN:
TSAN how I love thee. Let me non atomically count the ways…
- Philippe Hausler
This is *not* a good idea.

*Acknowledgments*
Thanks to everyone in the Swift Community working to make it an even more
vibrant place. And especially to those who worked on SE-0166
<https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt;
and SE-0185
<https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\.
Whom might notice large parts of a shared ideal, that made this proposal
much easier to write.

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

It is apparently ObjC atomic property being resurrected from the void.

These synthesised data structures are neither automatically correct nor automatically thread safe. The granularity of atomicity and correctness are largely dependent on the logic manipulating these individual states. So I am not sure if the proposal actually solves anything at just the level of property accesses.

ICYMI we already have the async-await proposal based on the actor model.

Regards
Anders

···

On 17 Nov 2017, at 7:50 AM, Christopher Heath via swift-evolution <swift-evolution@swift.org> wrote:

Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

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

Hi, I'm on vacation and can't quite answer in depth, but this proposal encourages all the wrong things in terms of performance. We know from 10 years of GCD that mixing async/sync, while possible, yields significant performance issues, and I'd rather not have something at the core of the language encouraging it.

Actors seem like a much better way of solving these problems IMO.

-Pierre

···

On Nov 16, 2017, at 1:50 PM, Christopher Heath via swift-evolution <swift-evolution@swift.org> wrote:

Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

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

Thanks Howard. You’re right asyncs don’t return values unless through a callback block. The internal compiler view for this constant is more meant to illustrate that the value can be read from multiple threads simultaneously safely. This almost certainly not the ideal way to represent it.

However, memory access to an immutable value is unlikely to ever race for access between 2 threads (as per SPL - Memory Safety: Memory Safety — The Swift Programming Language (Swift 5.7)). I think my thought pattern was that anytime a getter is called that it is actually a function in Swift, and that we should represent the idea of an ‘async’ like prevention of the unlikely simultaneous access; but I’m probably prematurely preventing possible violations of Exclusive Access. I’m open to ideas and edits that make this idea more clear.

···

On Nov 16, 2017, at 8:01 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

Sorry I don't get the code. In particular:

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Doesn't make sense `async`'s closure doesn't return anything.

What am I missing?

  -- Howard.

On 17 November 2017 at 10:50, Christopher Heath via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

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

+1 Howard, at least in the form of ‘let’ constants Swift ensures (or assumes, not really clear on that) that memory access will not conflict. Updated gist, to mention that and remove any implementation details relative to constants, however ‘async’s (and ‘sync's) with returns are still present in the code examples, and I’ll continue to work on a better way to describe them.

- Chris

···

On Nov 16, 2017, at 8:30 PM, Christopher Heath via swift-evolution <swift-evolution@swift.org> wrote:

Thanks Howard. You’re right asyncs don’t return values unless through a callback block. The internal compiler view for this constant is more meant to illustrate that the value can be read from multiple threads simultaneously safely. This almost certainly not the ideal way to represent it.

However, memory access to an immutable value is unlikely to ever race for access between 2 threads (as per SPL - Memory Safety: Memory Safety — The Swift Programming Language (Swift 5.7)). I think my thought pattern was that anytime a getter is called that it is actually a function in Swift, and that we should represent the idea of an ‘async’ like prevention of the unlikely simultaneous access; but I’m probably prematurely preventing possible violations of Exclusive Access. I’m open to ideas and edits that make this idea more clear.

On Nov 16, 2017, at 8:01 PM, Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:

Sorry I don't get the code. In particular:

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Doesn't make sense `async`'s closure doesn't return anything.

What am I missing?

  -- Howard.

On 17 November 2017 at 10:50, Christopher Heath via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

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

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

+1 Howard, at least in the form of ‘let’ constants Swift ensures (or assumes, not really clear on that) that memory access will not conflict. Updated gist, to mention that and remove any implementation details relative to constants, however ‘async’s (and ‘sync's) with returns are still present in the code examples, and I’ll continue to work on a better way to describe them.

- Chris

···

On Nov 16, 2017, at 8:30 PM, Christopher Heath via swift-evolution <swift-evolution@swift.org> wrote:

Thanks Howard. You’re right asyncs don’t return values unless through a callback block. The internal compiler view for this constant is more meant to illustrate that the value can be read from multiple threads simultaneously safely. This almost certainly not the ideal way to represent it.

However, memory access to an immutable value is unlikely to ever race for access between 2 threads (as per SPL - Memory Safety: Memory Safety — The Swift Programming Language (Swift 5.7)). I think my thought pattern was that anytime a getter is called that it is actually a function in Swift, and that we should represent the idea of an ‘async’ like prevention of the unlikely simultaneous access; but I’m probably prematurely preventing possible violations of Exclusive Access. I’m open to ideas and edits that make this idea more clear.

On Nov 16, 2017, at 8:01 PM, Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:

Sorry I don't get the code. In particular:

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Doesn't make sense `async`'s closure doesn't return anything.

What am I missing?

  -- Howard.

On 17 November 2017 at 10:50, Christopher Heath via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Good evening all,

I had a little idea and thought I’d pitch it. So here goes!

Synthesizing Concurrency aims to provide a foundation by which, regardless of concurrency implementation (however current proposal uses GCD examples for design), concurrency can be synthesized by the compiler and remove many lines of boilerplate code. Offering benefits to Application, Server and OS Developers alike; with easy and intelligent concurrency conformance. Also, should the community decide to head in another direction with concurrency this should be a relatively mappable idea to any Synchronization Primitive with a little work.

Thanks for looking, and I hope you like and want to contribute to the discussion of the Synthesizing Concurrency proposal. I’ve added a printout below. Please give it a read or check out the gist: NNNN-synthesize-concurrency.md · GitHub
Chris

Printout :
Synthesizing Concurrency
Proposal: SE-NNNN <https://gist.github.com/XNUPlay/a0d6f6c0afdb3286e324c480cb5c4290&gt;
Author: Christopher Heath: XNUPlay <https://github.com/xnuplay&gt;
Review Manager: TBD
Status: Pending Discussion
Implementation: Awaiting Implementation
Decision Notes: TBD

Introduction
Developers have to write large amounts of boilerplate code to support concurrency in complex types. This proposal offers a way for the compiler to automatically synthesize conformance to a high-level Concurrent protocol to reduce concurrent boilerplate code, in a set of scenarios where generating the correct implementation is known to be possible.
Specifically:
It aims to provide a high-level Swift protocol that offers opt-in concurrency support for any conformable type
It aims to provide a well-defined set of thread-safe, concurrent implementations for types, their properties, and methods.
It aims to provide a language/library compatible implementation with deadlock prevention.

Motivation
Building robust types in Swift can involve writing significant boilerplate code to support concurrency. By eliminating the complexity for the users, we make Concurrent types much more appealing to users and allow them to use their own types in optimized concurrent and parallel environments that require thread safety with no added effort on their part (beyond declaring the conformance).
Concurrency is typically not pervasive across many types, and for each one users must implement the concurrent code such that it performs some form of synchronization to prevent unexpected behavior.

Note: Due to it's current status in Swift and use in the Runtime <swift/Once.cpp at main · apple/swift · GitHub, examples are written in Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt;

// Concurrent Protocol - Dispatch Example
protocol Concurrent {
    // Synthesized Property
    var internalQueue: DispatchQueue { get }
}

What's worse is that if any functions or properties are added, removed, or changed, they must each have their own concurrency code and since it must be manually written, it's possible to get it wrong, either by omission or typographical error (async vs. sync).
Likewise, it becomes necessary when one wishes to modify an existing type that implements concurrency to do so without introducing bottlenecks or different forms of synchronization for some functions and not others, this leads to illegible and inefficient code that may defeat the purpose of implementing concurrency.
Crafting high-performance, readable concurrency code can be difficult and inconvenient to write.
Swift already derives conformance to a number of protocols, automatically synthesizing their inner-workings when possible. Since there is precedent for synthesized conformances in Swift, we propose extending it to concurrency in predictable circumstances.

Proposed solution
In general, we propose that a type synthesize conformance to Concurrent as long as the compiler has reasonable insight into the type. We describe the specific conditions under which these conformances are synthesized below, followed by the details of how the conformance requirements are implemented.

Requesting synthesis is opt-in
Users must opt-in to automatic synthesis by declaring their type as Concurrent without implementing any of its requirements. This conformance must be part of the original type declaration and not on an extension (see Synthesis in extensions below for more on this).
Any type that declares such conformance and satisfies the conditions below will cause the compiler to synthesize an implementation of an internalQueue and async or sync for all properties and methods on that type.
Making the synthesis opt-in—as opposed to automatic derivation without an explicit declaration—provides a number of benefits:
The syntax for opting in is natural; there is no clear analogue in Swift today for having a type opt out of a feature.
It requires users to make a conscious decision about the public API surfaced by their types. Types cannot accidentally "fall into" conformances that the user does not wish them to; a type that does not initially support Concurrent can be made to at a later date, but the reverse is a potentially breaking change.
The conformances supported by a type can be clearly seen by examining its source code; nothing is hidden from the user.
We reduce the work done by the compiler and the amount of code generated by not synthesizing conformances that are not desired and not used.
As will be discussed later, explicit conformance significantly simplifies the implementation for recursive types.

Overriding synthesized conformances
Any user-provided implementations of an internalQueue and use of async or sync will override the default implementations that would be provided by the compiler.

Defining conditions where synthesis is allowed
For example take the struct below, which contains all-kinds of properties; variable, constant, and computed.
struct Person {
    var name: String // Variable Property
    let birthday: Date // Constant Property
    var age: Int { // Computed Property
        /* - */
    }
}

Synthesized Requirements

Constant Properties
Constants are always accessed asynchronously.
A Constant is guaranteed to be immutable and therefore able to be read from any thread without concern for unexpected mutation.
The compiler sees this Constant as storage for a value.

// Compiler View - of a Constant Property
struct Person {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            return underlying_Birthday_Date_Value_Storage
        }
    }

    /* Computed Property */
}

After opting-in to the Concurrent protocol, the compiler synthesizes this implementation, adding an asynchronous access point to any Constant on a Concurrent type.

// Compiler View - of a Constant Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */

    // Constant Property
    let birthday: Date {
        get {
            internalQueue.async { // Immediately returns on calling thread
                return underlying_Birthday_Date_Value_Storage
            }
        }
    }

    /* Computed Property */
}

Synthesized requirements for Variable Properties
Variables are always accessed synchronously.
A Variable is mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation.
Just like a Constant, the compiler sees this Variable as storage for a value.

// Compiler View - of a Variable Property
struct Person {
    // Variable Property
    var name: String {
        get {
            return underlying_Name_String_Value_Storage
        }
        set (newValue) {
            underlying_Name_String_Value_Storage = newValue
        }
    }
    
    /* Constant Property */
    /* Computed Property */
}

Here the compiler synthesizes synchronous access (read or write) to any Variable on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    // Variable Property
    var name: String {
        get {
            internalQueue.sync { // Wait to ensure all mutation has finished
                return underlying_Name_String_Value_Storage
            }
        }
        set (newValue) {
            internalQueue.sync { // Schedule this mutation to happen, in order
                underlying_Name_String_Value_Storage = newValue
            }
        }
    }

    /* Constant Property */
    /* Computed Property */
}

Synthesized requirements for Computed Properties
Computed Properties are always accessed synchronously.
A Computed Property is essentially a function that gets called to create a value from other values. These other values can be mutable and therefore each thread must schedule writes and reads separately out of concern for possible mutation. (Note: If a computed property only accesses Constants, it should probably be a one-time set Constant; Swift <https://github.com/apple/swift&gt; could use a few proposals in this area.)

// Compiler View - of a Variable Property
struct Person {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        // Compute age from birthday; return
    }
}

Here the compiler synthesizes synchronous access (read or write) to any Computed Property on a Concurrent type.

// Compiler View - of a Variable Property on a Concurrent type
struct Person: Concurrent {
    /* Variable Property */
    /* Constant Property */

    // Computed Property
    var age: Int {
        internalQueue.sync { // Wait to ensure all mutation has finished
            // Compute age from birthday; return
        }
    }
}

Considerations for recursive types and abstraction
By making the synthesized conformances opt-in, recursive types have their requirements fall into place with no extra effort. In any cycle belonging to a recursive type, every type in that cycle must declare its conformance explicitly. If a type does so but cannot have its conformance synthesized because it does not satisfy the conditions above, then it is simply an error for that type and not something that must be detected earlier by the compiler in order to reason about all the other types involved in the cycle. (On the other hand, if conformance were implicit, the compiler would have to fully traverse the entire cycle to determine eligibility, which would make implementation much more complex).
With respect to abstraction, the idea that a synchronous function or property can access another synchronous function or property, introduces a problem: Deadlocking.

The Deadlock Problem
Or just Deadlocking, is a problem where a complex program cannot continue execution because one or more threads is waiting on a resource to become available or for another task to complete.
Anytime a synchronous function or property accesses another synchronous function or property; this is defined as a Deadlock, because the first cannot finish without the second being run and the second cannot execute without the first being finished.

Solving the Deadlock Problem
In complex functions where any number of synchronous and asynchronous calls can happen inside a larger scope it is required that the compiler know how to handle compilation of such functions, that may access many concurrent objects through a multitude of calls. Much like Automatic Reference Counting <https://en.wikipedia.org/wiki/Automatic_Reference_Counting&gt; increments and decrements a counter to determine whether an object should be marked for deallocation, we suggest that during compilation a call or set of calls is handled by evaluating their concurrent requirements.
I.e. When a call nests as such:

// Compiler View - of a Complex Function on a Concurrent type

func heavyLift() {
    syncFunction() // 1 Sync
    
    async() // 1 Async
    
    syncSomeFunction() // 2 Sync
    syncSomeOtherFunction() // 3 Sync
    
    asyncSomeFunction() // 2 Async
    asyncSomeOtherFunction() // 3 Async
}

The compiler should implement a non-modified function, exactly as it would today, and wrap each usage in-scope with an asynchronous or synchronous requirement.
Specifically:
If a higher-level function accesses only asynchronous functions or properties internally, that function can be executed in-order as a single asynchronous call and inlining access to all non-modified calls.
The same is true of synchronous functions or properties. They can be executed in-order as a single synchronous call and inlining access to existing non-modified calls.
If at any point a function or property, accesses an asynchronous and synchronous call then that function must be run as a single synchronous call.

Implementation details
Deadlock Prevention is then inherent by synthesis. The following example explains this through a chunk of modified, disassembled Swift code.

// Disassembly View - of an Integer Assignment without Thread-Safety
int __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0) { // Standard
    _swift_beginAccess(__T07Project6objectSiv, &var_30, 0x1, 0x0);
    *__T07Project6objectSiv = arg0;
    rax = _swift_endAccess(&var_30);
    return rax;
}

// Disassembly View - of an Integer Assignment with Asynchronous Access
int __T07Project14ConcurrentTypeC17functionWithAsyncySi5value_tF(int arg0) { // AsyncCall
    _swift_beginAccess(r13 + 0x10, &var_30, 0x0, 0x0);
    _swift_endAccess(&var_30, &var_30, 0x0, 0x0);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_60 = __NSConcreteStackBlock;
    var_98 = _Block_copy(&var_60);
    var_A0 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA_(&var_60, 0x18, __NSConcreteStackBlock);
    var_A1 = __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA0_();
    __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetF(var_A0, var_A1 & 0xff, __NSConcreteStackBlock, __T0So13DispatchQueueC0A0E5asyncySo0A5GroupCSg5group_AC0A3QoSV3qosAC0A13WorkItemFlagsV5flagsyyXB7executetFfA1_(&var_60, 0x18), var_98);
    rax = _swift_rt_swift_release(rax, var_A1 & 0xff);
    return rax;
}

// Disassembly View - of an Integer Assignment with Synchronous Access
int __T07Project14ConcurrentTypeC16functionWithSyncySi5value_tF(int arg0) { // SyncCall
    _swift_beginAccess(r13 + 0x10, &var_28, 0x0, 0x0);
    _swift_endAccess(&var_28, &var_28, 0x0, &var_28);
    rax = _swift_rt_swift_allocObject();
    
    // Call the Standard Function
    __T07Project14ConcurrentTypeC21functionWithoutSafetyySi5value_tF(int arg0)
    
    var_58 = __NSConcreteStackBlock;
    var_90 = _Block_copy(&var_58);
    _swift_rt_swift_release(rax, 0x18);
    dispatch_sync(*(r13 + 0x10), var_90);
    rax = _Block_release(var_90);
    return rax;
}

Here are 3 functions, one which assigns a value to an integer without any safety, like a non-concurrent type. As well as two more which call that function using asynchronous and synchronous access respectively.
The compiler determines which access should be used in a given scope, and places that scope inside a synchronous or asynchronous call.
Take a function which assigns this integer twice asynchronously:

    // Standard Call
    +---------------------------------------+
    > TwoAsyncs |
    > +-------------+ +-------------+ |
    > > AsyncCall | | AsyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
One might reason that this function would fire-and-forget those calls, but instead the compiler is rectifying them as a single async.

    // Single Asynchronous Call
    +---------------------------------------+
    > TwoAsyncs (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
This behavior is the same for synchronous-only functions; however, instead of rehashing lets look at the more interesting complex case. We start with this:

    // Standard Call
    +---------------------------------------+
    > AnyAsync/SyncCombination |
    > +-------------+ +-------------+ |
    > > AsyncCall | | SyncCall | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
But in actuality the compiler has composed a single synchronous call, since there is a sync call at any point in the function.

    // Single Synchronous Call
    +---------------------------------------+
    > AnyAsync/SyncCombination (Actually) |
    > +-------------+ +-------------+ |
    > > Standard | | Standard | |
    > +-------------+ +-------------+ |
    +---------------------------------------+
Let's do one more for added clarity.
    +-------------------------------------------------------------------------------------+
    > Combination |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs | | AnyAsync/SyncCombination | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > AsyncCall | | AsyncCall | | | | AsyncCall | | SyncCall | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+
Becomes:
    +-------------------------------------------------------------------------------------+
    > Combination //Sync |
    > +---------------------------------------+ +---------------------------------------+ |
    > > TwoAsyncs //Async | | AnyAsync/SyncCombination //Sync | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > > > Standard | | Standard | | | | Standard | | Standard | | |
    > > +-------------+ +-------------+ | | +-------------+ +-------------+ | |
    > +---------------------------------------+ +---------------------------------------+ |
    +-------------------------------------------------------------------------------------+

We've already made great decisions about thread-safety by implementing SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; for Value Types
SE-0035 Limiting Inout Capture <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt; actually provides us with a proof-of-concept as to why Value Types should not be asynchronously mutated inside a closure.

Source compatibility
By making the conformance opt-in, this is a purely additive change that should not affect existing code and should be easily applicable to stdlib types.
Some current types using Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; should be audited for recursive-implementation, if a user wishes to replace their own implementation with this synthesized one.

Effect on ABI stability
This feature is purely additive and should not change ABI.
(Additionally, see Explicit Manglings for Sync/Async below for more on this.)

Effect on API resilience
N/A.

Alternatives considered
In order to realistically scope this proposal, we considered but ultimately deferred the following items, some of which could be proposed additively in the future.

Synthesis in extensions
Requirements will be synthesized only for protocol conformances that are part of the type declaration itself; conformances added in extensions will not be synthesized.
However, to align with Codable in the context of SR-4920 <Issues · apple/swift-issues · GitHub, we will also currently forbid synthesized requirements in extensions in the same file; this specific case can be revisited later for all derived conformances.

Explicit Manglings
Because accesses are compiled and their async or sync wrappers are deterministic from use case, it may be useful to create specific Manglings; this is optional.

Embedding or Building Dispatch
Dispatch already provides us with a very powerful and exacting standard for concurrency in Swift, it would be even more useful if embedded directly in the runtime with replacements like that currently in the Runtime <swift/Once.cpp at main · apple/swift · GitHub.
I feel as if most of the reason this would be frowned upon is a Swift desire for style, code cleanliness and some hope of a 'better' (whatever that means to you) solution.
Yet, we could add the existing library to the Runtime or even rewrite Grand Central Dispatch <https://github.com/apple/swift-corelibs-libdispatch&gt; as a Swift project and embed it in the Standard Library.
Ideally, this would be deferred to a separate Swift Evolution Proposal.

Keyword Overrides
It is worth mentioning a Keyword could be used for overriding a function and defining explicit behavior as sync or async. However, this opens the door to misuse and incorrect code that can only be debugged at runtime with TSAN. And while we love TSAN:
  TSAN how I love thee. Let me non atomically count the ways…
                - Philippe Hausler
This is not a good idea.

Acknowledgments
Thanks to everyone in the Swift Community working to make it an even more vibrant place. And especially to those who worked on SE-0166 <https://github.com/apple/swift-evolution/blob/master/proposals/0166-swift-archival-serialization.md&gt; and SE-0185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md&gt;\. Whom might notice large parts of a shared ideal, that made this proposal much easier to write.

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

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