Skip to content

Instantly share code, notes, and snippets.

@DougGregor
DougGregor / initiating-async-work.md
Created Apr 26, 2021
Initiating async work from synchronous code
View initiating-async-work.md

Initiating async work from synchronous code

Motivation

Swift async functions can only directly be called from other async functions. In synchronous code, the only mechanism provided by the Swift Concurrency model to create asynchronous work is detach. The detach operation creates a new, detached task that is completely independent of the code that initiated the detach: the closure executes concurrently, is independent of any actor unless it explicitly opts into an actor, and does not inherit certain information (such as priority).

Detached tasks are important and have their place, but they don't map well to cases where the natural "flow" of control is from the synchronous function into async code, e.g., when reacting to an event triggered in a UI:

@MainActor func saveResults() {
@DougGregor
DougGregor / parallel_map.swift
Created Dec 24, 2020
Swift async/await implementation of a parallel map
View parallel_map.swift
extension Collection {
func parallelMap<T>(
parallelism requestedParallelism: Int? = nil,
_ transform: @escaping (Element) async throws -> T
) async throws -> [T] {
let defaultParallelism = 2
let parallelism = requestedParallelism ?? defaultParallelism
let n = self.count
if n == 0 {
@DougGregor
DougGregor / preventing-data-races.md
Created Dec 20, 2020
Preventing Data Races in the Swift Concurrency Model
View preventing-data-races.md

Preventing Data Races in the Swift Concurrency Model

One of the goals of the concurrency effort is to prevent data races. This document describes the approach taken to preventing data races overall, by categorizing the sources of data races and describing how they are addressed with other proposals in the Swift Concurrency effort.

Data races

A data race occurs when two threads access the same memory concurrently and at least one of the accesses can change the value. Within the safe subset of Swift (e.g., ignoring the use of UnsafeMutablePointer and related types), the memory in question is always a stored property. There are several different categories of stored properties that need to be considered for data races:

  • Global and static stored properties:
@DougGregor
DougGregor / concurrent_merge_sort_algorithm_club.swift
Created Dec 12, 2020
Concurrent merge sort ported from the Swift Algorithm Club site
View concurrent_merge_sort_algorithm_club.swift
// Ported from https://www.raywenderlich.com/741-swift-algorithm-club-swift-merge-sort
func mergeSort<T: Comparable>(_ array: [T]) async -> [T] {
guard array.count > 1 else { return array }
let middleIndex = array.count / 2
async let leftArray = await mergeSort(Array(array[0..<middleIndex]))
async let rightArray = await mergeSort(Array(array[middleIndex..<array.count]))
return merge(await leftArray, await rightArray)
@DougGregor
DougGregor / actor_counters.swift
Last active Dec 18, 2020
Actor counters example
View actor_counters.swift
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#endif
actor class Counter {
private var value = 0
private let scratchBuffer: UnsafeMutableBufferPointer<Int>
@DougGregor
DougGregor / SwiftConcurrencyDependencies.svg
Created Dec 2, 2020
Swift Concurrency Proposal Dependencies
View SwiftConcurrencyDependencies.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@DougGregor
DougGregor / scan-type-metadata.patch
Created Aug 9, 2019
Scan type metadata to populate the context descriptor cache
View scan-type-metadata.patch
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index 49ff72a487a..472dcbe0afd 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -237,7 +237,8 @@ struct TypeMetadataPrivateState {
llvm::DenseMap<llvm::StringRef,
llvm::TinyPtrVector<const ContextDescriptor *>>
ContextDescriptorCache;
- size_t ContextDescriptorLastSectionScanned = 0;
+ size_t ConformanceDescriptorLastSectionScanned = 0;
@DougGregor
DougGregor / swift_cxx_interop_first_steps.md
Created Jul 18, 2019
First steps for Swift/C++ interoperability
View swift_cxx_interop_first_steps.md

First steps for Swift/C++ Interoperability

Just a quick brain dump of "first steps" to move Swift/C++ interoperability forward. While there are many big and interesting design questions for a good interoperability story, there are also a large number of implementation tasks that can proceed independently of those design discussions (and often in parallel). This list focuses on those implementation tasks:

  1. (DONE) Add a flag -enable-cxx-interop to the frontend, and have it enable (Objective-)C++ mode in the Clang importer.
  2. Add a lit configuration flag to enable -enable-cxx-interop for the full Swift testsuite and fix all of the issues that prevent (Objective-)C code from being imported correctly when it's compiled as C++. The testsuite will likely need a lot of extern "C" annotations throughout it's headers---those fixes can be committed to the testsuite behind appropriate #ifdefs.
  3. Import C++ namespaces as Swift enums that have no cases (so-called "uninhabited enums") so the C++ lexical struct
@DougGregor
DougGregor / dynamic_member_lookup_environment.swift
Created May 2, 2018
Using Swift 4.2's @dynamicMemberLookup to expose environment variables
View dynamic_member_lookup_environment.swift
import Darwin
@dynamicMemberLookup
struct Environment {
subscript(dynamicMember name: String) -> String? {
get {
guard let value = getenv(name) else { return nil }
return String(validatingUTF8: value)
}