Skip to content

Instantly share code, notes, and snippets.

DougGregor /
Last active May 18, 2024 11:19
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 /
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 /
Created April 26, 2021 20:26
Initiating async work from synchronous code

Initiating async work from synchronous code


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 / 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 /
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 / concurrent_merge_sort_algorithm_club.swift
Created December 12, 2020 06:09
Concurrent merge sort ported from the Swift Algorithm Club site
// Ported from
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 / actor_counters.swift
Last active December 18, 2020 04:55
Actor counters example
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
actor class Counter {
private var value = 0
private let scratchBuffer: UnsafeMutableBufferPointer<Int>
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 / scan-type-metadata.patch
Created August 9, 2019 00:15
Scan type metadata to populate the context descriptor cache
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::TinyPtrVector<const ContextDescriptor *>>
- size_t ContextDescriptorLastSectionScanned = 0;
+ size_t ConformanceDescriptorLastSectionScanned = 0;