Skip to content

Instantly share code, notes, and snippets.

@DougGregor
DougGregor / preventing-data-races.md
Created December 20, 2020 06:49
Preventing Data Races in the Swift Concurrency Model

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 / parallel_map.swift
Created December 24, 2020 01:10
Swift async/await implementation of a parallel map
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 / SwiftConcurrencyDependencies.svg
Created December 2, 2020 00:39
Swift Concurrency Proposal Dependencies
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@DougGregor
DougGregor / concurrent_merge_sort_algorithm_club.swift
Created December 12, 2020 06:09
Concurrent merge sort ported from the Swift Algorithm Club site
// 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 / macros-dashboard.md
Last active December 7, 2023 05:28
Swift Macros Dashboard

Swift Macros Dashboard

Macros are a power feature in a number of programming languages that make the language more extensible. Swift has always sought to enable expressive libraries through its use of type inference, generics, and general approach toward clarity of use. Macros in Swift are intended to improve expressiveness without sacrificing clarity.

This gist provides a "dashboard" with links to the various documents and example projects that are part of the Swift Macros effort. Head on over to the Swift Forums if you have questions!

Overview and examples:

  • Macros vision document: lays out the overall motivation, goals, and approach we're taking in the implementation of macros in Swift.
  • Example macros repository: contains a number of example macros that demonstrate the capabilities of the macro system and how it integrates into the language. This
@DougGregor
DougGregor / macros.md
Last active October 24, 2023 16:42
A possible vision for macros in Swift

A Possible Vision for Macros in Swift

As Swift evolves, it gains new language features and capabilities. There are different categories of features: some fill in gaps, taking existing syntax that is not permitted and giving it a semantics that fit well with the existing language, with features like conditional conformance or allowing existential values for protocols with Self or associated type requirements. Others introduce new capabilities or paradigms to the language, such as the addition of concurrency or comprehensive reflection.

There is another large category of language features that provide syntactic sugar to eliminate common boilerplate, taking something that can be written out in long-form and making it more concise. Such features don't technically add any expressive power to the language, because you can always write the long-form version, but their effect can be transformational if it enables use cases that would otherwise have been unwieldy. The synthesis of Codable conformances, for ex

@DougGregor
DougGregor / swift_cxx_interop_first_steps.md
Created July 18, 2019 17:32
First steps for Swift/C++ interoperability

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 16:59
Using Swift 4.2's @dynamicMemberLookup to expose environment variables
import Darwin
@dynamicMemberLookup
struct Environment {
subscript(dynamicMember name: String) -> String? {
get {
guard let value = getenv(name) else { return nil }
return String(validatingUTF8: value)
}
@DougGregor
DougGregor / initiating-async-work.md
Created April 26, 2021 20:26
Initiating async work from synchronous code

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() {