The Sendable Protocol
Mark types safe to cross concurrency domains.
The Sendable Protocol is a free Swift Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Sendable Means
Sendable is a marker protocol. A type that conforms promises it is safe to share across concurrency domains without introducing data races.
It has no methods; it is a compiler-checked guarantee about thread safety.
protocol Sendable {}Value Types Are Often Sendable
Structs and enums whose stored properties are all Sendable can conform automatically.
Because values are copied when passed, each task gets its own independent copy.
struct User: Sendable {
let id: Int
let name: String
}Implicit Conformance
Many value types get Sendable implicitly: non-public frozen structs and enums with Sendable members, tuples of Sendable types, and metatypes.
You often do not write : Sendable at all for internal value types.
enum Direction { case north, south, east, west }
// Implicitly Sendable: no associated non-Sendable dataWhen a Struct Is NOT Sendable
If a struct holds a non-Sendable stored property, it is not Sendable.
Here the class reference makes shared mutable state reachable, so the compiler refuses automatic conformance.
final class Box { var value = 0 }
struct Wrapper { // not Sendable
let box: Box // class with mutable state
}Classes and Sendable
Classes are reference types, so copies share the same instance. A class is only Sendable if it is final and all its stored properties are immutable and Sendable.
final class ImmutablePoint: Sendable {
let x: Double
let y: Double
init(x: Double, y: Double) { self.x = x; self.y = y }
}@unchecked Sendable
Sometimes you know a class is thread-safe (it guards state with a lock) but the compiler cannot prove it. Use @unchecked Sendable to assert safety manually.
This is an escape hatch: you take responsibility for correctness.
import Foundation
final class Cache: @unchecked Sendable {
private let lock = NSLock()
private var storage: [String: Int] = [:]
func set(_ k: String, _ v: Int) {
lock.lock(); defer { lock.unlock() }
storage[k] = v
}
}@Sendable Closures
Closures can also be marked @Sendable. Such a closure may be passed across concurrency boundaries, so the compiler verifies it captures only Sendable values.
func run(_ work: @Sendable () -> Void) {
work()
}
let name = "Ada" // immutable, Sendable
run { print(name) }Capturing Mutable State Is Rejected
A @Sendable closure cannot capture a mutable variable, because two tasks could mutate it concurrently.
The compiler flags the capture below.
var counter = 0
// Error: @Sendable closure captures mutable var
// run { counter += 1 }Sendable in Async APIs
Concurrency entry points require Sendable. Task closures are @Sendable, and values passed to other actors must be Sendable.
This is how the type system stops non-thread-safe data from leaking across tasks.
func process(_ user: User) async {
Task {
// user is Sendable, safe to capture
print(user.name)
}
}Generic Sendable Constraints
You can require Sendable in generics. A function that spawns tasks with its argument should constrain that argument to Sendable.
func dispatch<T: Sendable>(_ value: T) {
Task { print(value) }
}Sendable vs Actor
Sendable answers "is this value safe to pass?" while an actor answers "how do I protect mutable state?"
They compose: actors are implicitly Sendable because access to their state is serialized.
actor Logger { } // actors are implicitly SendableQuick Check: Sendable
Test your understanding of Sendable conformance.
Recap: The Sendable Protocol
Sendable marks types safe to cross concurrency boundaries. Immutable value types conform automatically; final immutable classes can conform; thread-safe classes use @unchecked Sendable.
@Sendable closures may only capture Sendable values, and async APIs require Sendable to prevent unsafe sharing. Together with actors, Sendable forms the type-level foundation of Swift data-race safety.
Frequently asked questions
Is the “The Sendable Protocol” lesson free?
Yes — the full text of “The Sendable Protocol” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “The Sendable Protocol”?
Mark types safe to cross concurrency domains. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “The Sendable Protocol” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Data Race Problem
- The Sendable Protocol
- Actor Isolation and nonisolated
- Migrating to Strict Concurrency