Use when optimizing large value type performance, working with noncopyable types, reducing ARC traffic, or using InlineArray/Span for zero-copy memory access. Covers borrowing, consuming, inout modifiers, consume operator, ~Copyable types, InlineArray, Span, value generics.
Optimizes Swift performance using ownership modifiers, InlineArray, and Span for zero-copy memory access and noncopyable types.
npx claudepluginhub charleswiltgen/axiomThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Explicit ownership modifiers for performance optimization and noncopyable type support.
✅ Use when:
~Copyable)❌ Don't use when:
| Modifier | Ownership | Copies | Use Case |
|---|---|---|---|
| (default) | Compiler chooses | Implicit | Most cases |
borrowing | Caller keeps | Explicit copy only | Read-only, large types |
consuming | Caller transfers | None needed | Final use, factories |
inout | Caller keeps, mutable | None | Modify in place |
| Context | Default | Reason |
|---|---|---|
| Function parameters | borrowing | Most params are read-only |
| Initializer parameters | consuming | Usually stored in properties |
| Property setters | consuming | Value is stored |
Method self | borrowing | Methods read self |
struct LargeBuffer {
var data: [UInt8] // Could be megabytes
}
// ❌ Default may copy
func process(_ buffer: LargeBuffer) -> Int {
buffer.data.count
}
// ✅ Explicit borrow — no copy
func process(_ buffer: borrowing LargeBuffer) -> Int {
buffer.data.count
}
struct Builder {
var config: Configuration
// Consumes self — builder invalid after call
consuming func build() -> Product {
Product(config: config)
}
}
let builder = Builder(config: .default)
let product = builder.build()
// builder is now invalid — compiler error if used
With borrowing, copies must be explicit:
func store(_ value: borrowing LargeValue) {
// ❌ Error: Cannot implicitly copy borrowing parameter
self.cached = value
// ✅ Explicit copy
self.cached = copy value
}
Transfer ownership explicitly:
let data = loadLargeData()
process(consume data)
// data is now invalid — compiler prevents use
For ~Copyable types, ownership modifiers are required:
struct FileHandle: ~Copyable {
private let fd: Int32
init(path: String) throws {
fd = open(path, O_RDONLY)
guard fd >= 0 else { throw POSIXError.errno }
}
borrowing func read(count: Int) -> Data {
// Read without consuming handle
var buffer = [UInt8](repeating: 0, count: count)
_ = Darwin.read(fd, &buffer, count)
return Data(buffer)
}
consuming func close() {
Darwin.close(fd)
// Handle consumed — can't use after close()
}
deinit {
Darwin.close(fd)
}
}
// Usage
let file = try FileHandle(path: "/tmp/data.txt")
let data = file.read(count: 1024) // borrowing
file.close() // consuming — file invalidated
class ExpensiveObject { /* ... */ }
// ❌ Default: May retain/release
func inspect(_ obj: ExpensiveObject) -> String {
obj.description
}
// ✅ Borrowing: No ARC traffic
func inspect(_ obj: borrowing ExpensiveObject) -> String {
obj.description
}
struct Transaction {
var amount: Decimal
var recipient: String
// After commit, transaction is consumed
consuming func commit() async throws {
try await sendToServer(self)
// self consumed — can't modify or reuse
}
}
// ❌ Unnecessary — Int is trivially copyable
func add(_ a: borrowing Int, _ b: borrowing Int) -> Int {
a + b
}
// ✅ Let compiler optimize
func add(_ a: Int, _ b: Int) -> Int {
a + b
}
func cache(_ value: borrowing LargeValue) {
// ❌ Compile error
self.values.append(value)
// ✅ Explicit copy required
self.values.append(copy value)
}
// ❌ Consumes unnecessarily — caller loses access
func validate(_ data: consuming Data) -> Bool {
data.count > 0
}
// ✅ Borrow for read-only
func validate(_ data: borrowing Data) -> Bool {
data.count > 0
}
Know the constraints before adopting ~Copyable:
| Limitation | Impact | Workaround |
|---|---|---|
Can't store in Array, Dictionary, Set | Collections require Copyable | Use Optional<T> wrapper or manage manually |
| Can't use with most generics | <T> implicitly means <T: Copyable> | Use <T: ~Copyable> (requires library support) |
| Protocol conformance restricted | Most protocols require Copyable | Use ~Copyable protocol definitions |
| Can't capture in closures by default | Closures copy captured values | Use borrowing closure parameters |
| No existential support | any ~Copyable doesn't work | Use generics instead |
Common compiler errors when adopting ownership modifiers:
// Error: "Cannot implicitly copy a borrowing parameter"
// Fix: Add explicit `copy` or change to consuming
func store(_ v: borrowing LargeValue) {
self.cached = copy v // ✅ Explicit copy
}
// Error: "Noncopyable type cannot be used with generic"
// Fix: Constrain generic to ~Copyable
func use<T: ~Copyable>(_ value: borrowing T) { } // ✅
// Error: "Cannot consume a borrowing parameter"
// Fix: Change to consuming if you need ownership transfer
func takeOwnership(_ v: consuming FileHandle) { } // ✅
// Error: "Missing 'consuming' or 'borrowing' modifier"
// Fix: ~Copyable types require explicit ownership on all methods
struct Token: ~Copyable {
borrowing func peek() -> String { ... } // ✅ Explicit
consuming func redeem() { ... } // ✅ Explicit
}
When NOT to use ~Copyable:
consuming func on regular types as a lighter alternative for "use once" semanticsFixed-size, stack-allocated array using value generics. No heap allocation, no reference counting, no copy-on-write.
@frozen struct InlineArray<let count: Int, Element> where Element: ~Copyable
The let count: Int is a value generic — the size is part of the type, checked at compile time. InlineArray<3, Int> and InlineArray<4, Int> are different types.
| Use InlineArray | Use Array |
|---|---|
| Size known at compile time | Size changes at runtime |
| Hot path needing zero heap allocation | Copy-on-write sharing is beneficial |
| Embedded in other value types | Frequently copied between variables |
| Performance-critical inner loops | General-purpose collection needs |
// Fixed-size, inline storage — no heap allocation
var matrix: InlineArray<9, Float> = [1, 0, 0, 0, 1, 0, 0, 0, 1]
matrix[4] = 2.0
// Type inference works for count, element, or both
let rgb: InlineArray = [0.2, 0.4, 0.8] // InlineArray<3, Double>
// Eager copy on assignment (no COW)
var copy = matrix
copy[0] = 99 // matrix[0] still 1
Elements are stored contiguously with no overhead:
MemoryLayout<InlineArray<3, UInt16>>.size // 6 (2 bytes × 3)
MemoryLayout<InlineArray<3, UInt16>>.alignment // 2 (same as UInt16)
InlineArray supports noncopyable elements — enables fixed-size collections of unique resources:
struct Sensor: ~Copyable { var id: Int }
var sensors: InlineArray<4, Sensor> = ... // Valid: ~Copyable elements allowed
Span replaces unsafe pointers with compile-time-enforced safe memory views. Zero runtime overhead.
| Type | Access | Use Case |
|---|---|---|
Span<Element> | Read-only elements | Safe iteration, passing to algorithms |
MutableSpan<Element> | Read-write elements | In-place mutation without copies |
RawSpan | Read-only bytes | Binary parsing, protocol decoding |
MutableRawSpan | Read-write bytes | Binary serialization |
OutputSpan | Write-only | Initializing new collection storage |
UTF8Span | Read-only UTF-8 | Safe Unicode processing |
Containers with contiguous storage expose .span and .mutableSpan:
let array = [1, 2, 3, 4]
let span = array.span // Span<Int>
var mutable = [10, 20, 30]
var ms = mutable.mutableSpan // MutableSpan<Int>
ms[0] = 99
Spans are non-escapable — the compiler guarantees they cannot outlive the container they borrow from:
// ❌ Cannot return span that depends on local variable
func getSpan() -> Span<UInt8> {
let array: [UInt8] = Array(repeating: 0, count: 128)
return array.span // Compile error
}
// ❌ Cannot capture span in closure
let span = array.span
let closure = { span.count } // Compile error
// ❌ Cannot access span after mutating original
var array = [1, 2, 3]
let span = array.span
array.append(4)
// span[0] // Compile error: container was modified
These constraints prevent use-after-free, dangling pointers, and overlapping mutation at compile time with zero runtime cost.
| Span | UnsafeBufferPointer | |
|---|---|---|
| Memory safety | Compile-time enforced | Manual, error-prone |
| Lifetime tracking | Automatic, non-escapable | None — dangling pointers possible |
| Runtime overhead | Zero | Zero |
| Use-after-free | Impossible | Common source of crashes |
func parseHeader(_ data: borrowing [UInt8]) -> Header {
var raw = data.span.rawSpan // RawSpan over the array's bytes
let magic = raw.unsafeLoadUnaligned(as: UInt32.self)
raw = raw.extracting(droppingFirst: 4)
let version = raw.unsafeLoadUnaligned(as: UInt16.self)
return Header(magic: magic, version: version)
}
UnsafeBufferPointer — same performance, compile-time safetyRawSpan for byte-level accessUTF8Span for safe string byte accessValue generics allow integer values as generic parameters, making sizes part of the type system:
// `let count: Int` is a value generic parameter
struct InlineArray<let count: Int, Element> { ... }
// Different counts = different types
let a: InlineArray<3, Int> = [1, 2, 3]
let b: InlineArray<4, Int> = [1, 2, 3, 4]
// a = b // Compile error: different types
Currently limited to Int parameters. Enables stack-allocated, fixed-size abstractions where the compiler verifies size compatibility at compile time.
Need explicit ownership?
├─ Working with ~Copyable type?
│ └─ Yes → Required (borrowing/consuming)
├─ Fixed-size collection, no heap allocation?
│ └─ Yes → InlineArray<let count, Element>
├─ Need safe pointer-like access to contiguous memory?
│ ├─ Read-only? → Span<Element>
│ ├─ Mutable? → MutableSpan<Element>
│ └─ Raw bytes? → RawSpan / MutableRawSpan
├─ Large value type passed frequently?
│ ├─ Read-only? → borrowing
│ └─ Final use? → consuming
├─ ARC traffic visible in profiler?
│ ├─ Read-only? → borrowing
│ └─ Transferring ownership? → consuming
└─ Otherwise → Let compiler choose
Swift Evolution: SE-0377, SE-0453 (Span), SE-0451 (InlineArray), SE-0452 (value generics)
WWDC: 2024-10170, 2025-245, 2025-312
Docs: /swift/inlinearray, /swift/span
Skills: axiom-swift-performance, axiom-swift-concurrency
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.