Swift reference

Toolchain invocation, package manifests, attribute and modifier tables, the operator precedence hierarchy, the standard library's protocol structure, and the official naming conventions. The language itself is described in the Swift article; this page is the lookup companion to it.

Toolchain and command line

A Swift toolchain is a single download containing the compiler, standard library, package manager, debugger, formatter, language server, and documentation compiler. On macOS it is embedded in Xcode and also available standalone; on Linux and Windows it is installed from swift.org or through swiftly, the official toolchain manager, which installs several toolchains side by side and selects between them per project.

The commands that make up a Swift installation.

CommandPurposeTypical invocationNotes
swiftcThe compiler driverswiftc main.swift -O -o appDirect invocation; used for single files and by other build systems
swiftREPL when given no argumentsswiftInteractive evaluation
swift buildBuilds the package in the current directoryswift build -c releaseThe normal entry point
swift runBuilds and runs an executable productswift run MyTool --verboseArguments after the target name go to the program
swift testBuilds and runs the test targetsswift test --filter ParserTestsRuns both Swift Testing and XCTest suites
swift packageManifest and dependency operationsswift package resolve, update, cleanAlso hosts package plugins
swift-formatFormatter and linterswift-format --in-place Sources/Ships with the toolchain since 6.0
sourcekit-lspLanguage serverStarted by the editorPowers VS Code, Neovim, and others
lldbDebugger with the Swift type checker embeddedlldb .build/debug/MyToolExpression evaluation uses the real compiler
doccDocumentation compilerswift package generate-documentationBuilds the DocC archive from doc comments and articles

Source: Swift.org toolchain documentation and swift --help for the current release.

The compiler flags that appear most often in real build configurations.

FlagEffectScope
-swift-version 6Selects the language modePer module
-enable-upcoming-feature XOpts into one future behaviour earlyPer module
-strict-concurrency=completeFull data-isolation checking in the Swift 5 modePer module
-O / -OnoneOptimised / unoptimised buildPer module
-OsizeOptimise for code size rather than speedPer module
-wmoWhole-module optimisation: compile the module as one unitPer module
-enable-library-evolutionEmit a stable module interface for binary distributionPer module
-cxx-interoperability-mode=defaultEnable C++ interoperabilityPer module
-sanitize=address|thread|undefinedLink a runtime sanitizerPer build
-warnings-as-errorsFail the build on any warningPer build
-emit-sil / -emit-irDump the intermediate representationDiagnostic use

Source: swiftc -help and the Swift compiler documentation. Package manifests set most of these through swiftSettings rather than by passing flags directly.

Back to top

Swift Package Manager

SwiftPM is part of the toolchain, not a separate project. A package is a directory with a Package.swift manifest, which is itself a Swift program executed by the package manager: the first line is a swift-tools-version comment that tells SwiftPM which manifest API to compile it against, and therefore also sets the default language mode.

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "Atlas",
    platforms: [.macOS(.v14), .iOS(.v17)],
    products: [
        .library(name: "AtlasCore", targets: ["AtlasCore"]),
        .executable(name: "atlas", targets: ["AtlasCLI"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
        .package(url: "https://github.com/apple/swift-log", .upToNextMinor(from: "1.6.0")),
    ],
    targets: [
        .target(
            name: "AtlasCore",
            dependencies: [.product(name: "Logging", package: "swift-log")],
            swiftSettings: [
                .swiftLanguageMode(.v6),
                .enableUpcomingFeature("ExistentialAny"),
                .define("ATLAS_INTERNAL_CHECKS", .when(configuration: .debug)),
            ]
        ),
        .executableTarget(
            name: "AtlasCLI",
            dependencies: [
                "AtlasCore",
                .product(name: "ArgumentParser", package: "swift-argument-parser"),
            ]
        ),
        .testTarget(name: "AtlasCoreTests", dependencies: ["AtlasCore"]),
    ],
    swiftLanguageModes: [.v6]
)

The seven target types.

Target typeWhat it buildsDefault source location
.targetA library module compiled from Swift sourcesSources/<name>/
.executableTargetA module with an entry pointSources/<name>/
.testTargetTest module; not built for releaseTests/<name>/
.macroCompiler plugin implementing a macroSources/<name>/
.systemLibraryModule map wrapping an installed C librarySources/<name>/module.modulemap
.binaryTargetPrebuilt XCFramework or artifact bundleLocal path or remote URL with checksum
.pluginBuild-tool or command pluginPlugins/<name>/

Source: the PackageDescription API reference for tools version 6. Conventional layout means most packages need no explicit path: arguments.

Dependency resolution follows semantic versioning and records exact resolved versions in Package.resolved, which is committed. Version requirements are expressed as from: (up to the next major), .upToNextMinor(from:), an exact version, a branch, or a revision; the last two are accepted for a root package but rejected in a package that is itself a dependency, which prevents unpinned transitive requirements.

Plugins are code you run at build time. Build-tool plugins and macro implementations execute on the developer's machine during compilation. SwiftPM sandboxes them and asks for explicit confirmation before running a plugin from a dependency; in CI, that confirmation is a flag, so decide it deliberately rather than adding --disable-sandbox to make an error go away.

Back to top

Testing

Two frameworks coexist. XCTest is the older, Objective-C-derived framework; Swift Testing, introduced with Swift 6, is written for the modern language and uses macros so that a single #expect reports the values of every sub-expression in a failed assertion. Both run under swift test and can live in the same target, which is what makes incremental adoption practical.

The two frameworks compared on the points that affect how tests are written.

AspectSwift TestingXCTest
Declaration@Test func example()func testExample() in an XCTestCase
Assertions#expect(x == y), #requireXCTAssertEqual and roughly forty siblings
Failure detailMacro captures the sub-expression valuesMessage string supplied by the caller
Grouping@Suite struct, nesting by typeSubclassing XCTestCase
Parameterisation@Test(arguments:) over any collectionManual loops or generated methods
ConcurrencyTests run in parallel by default; async nativeSerial by default
Setup and teardowninit and deinit of the suite typesetUp/tearDown
Traits.tags, .enabled(if:), .timeLimitScheme configuration
Platform supportAll Swift platformsAll Swift platforms

Source: the Swift Testing documentation and the XCTest reference. Swift Testing does not replace XCTest for UI and performance testing on Apple platforms, which remain XCTest-only.

import Testing
@testable import AtlasCore

@Suite("Version parsing")
struct VersionParsingTests {

    @Test("Accepts well-formed semantic versions",
          arguments: ["6.3.3", "1.0.0", "10.20.30"])
    func parsesValid(_ input: String) throws {
        let version = try #require(Version(input))
        #expect(version.description == input)
    }

    @Test(.tags(.regression))
    func rejectsTrailingText() {
        #expect(Version("6.3.3-beta") == nil)
    }
}

Back to top

Attribute reference

Attributes are written with a leading @ before the declaration or type they modify. They fall into three positions: declaration attributes, type attributes, and one switch-case attribute (@unknown, which future-proofs a switch over a non-frozen enumeration).

Declaration attributes, grouped by what they are for rather than alphabetically.

AttributeCategoryEffect
@attached(...)MacroDeclares an attached macro role
@freestanding(...)MacroDeclares a freestanding macro role
@available(...)AvailabilityPlatform, version, deprecation, obsoletion, and noasync
@backDeployed(before:)AvailabilityShip a function's body to older OS versions in the client
@discardableResultDiagnosticsSuppresses the unused-result warning
@warn_unqualified_accessDiagnosticsWarns when a member is called without qualification
@dynamicCallableDynamicType may be called with a keyword or positional argument list
@dynamicMemberLookupDynamicMember access is resolved at runtime by subscript
@frozenEvolutionFixes stored layout or enum cases across library versions
@inlinableEvolutionExposes the body to clients for cross-module inlining
@usableFromInlineEvolutionMakes an internal symbol usable from an inlinable body
@globalActorConcurrencyDeclares a type as a global actor
@preconcurrencyConcurrencyRelaxes checking against pre-concurrency code
@uncheckedConcurrencyAsserts Sendable without compiler proof
@propertyWrapperMetaprogrammingDeclares a property wrapper type
@resultBuilderMetaprogrammingDeclares a result-builder type
@mainEntry pointMarks the type providing static func main()
@objc / @nonobjcInteropExpose to, or hide from, the Objective-C runtime
@objcMembersInteropApplies @objc to a class and its members
@NSCopying / @NSManagedInteropFoundation and Core Data storage behaviour
@testableTestingImport a module with internal symbols visible
@exportModulesRe-export definitions to client modules (documented from 6.2.3)

Source: The Swift Programming Language, Attributes chapter. Interface Builder attributes (@IBAction, @IBOutlet, @IBDesignable, @IBInspectable) and the deprecated @UIApplicationMain/@NSApplicationMain are omitted.

The four type attributes.

AttributeEffect
@autoclosureWraps the argument expression in a closure, deferring evaluation
@escapingThe closure may outlive the call; required for stored closures
@SendableThe function may cross isolation boundaries
@convention(c|block|swift)Selects the calling convention for a function type

Type attributes appear on a type, most often a function type in a parameter position.

The evolution attributes are promises. @frozen and @inlinable move implementation details into your clients' compiled binaries. Removing either later is a binary-breaking change, so apply them only to declarations whose representation you are willing to freeze permanently, and only in libraries built with -enable-library-evolution.

Back to top

Declaration modifiers

Modifiers are keywords or context-sensitive keywords written between a declaration's attributes and the keyword that introduces it. Access-level modifiers are covered in the Access control section of the language article; each also accepts a (set) argument to give a setter narrower access than its getter.

Non-access modifiers.

ModifierEffect
classMember belongs to the class itself; overridable unless final
staticMember belongs to the type; equivalent to class final on a class
finalClass cannot be subclassed, or member cannot be overridden
overrideReplaces a superclass member; required, so accidental shadowing is an error
requiredEvery subclass must implement this initializer
convenienceInitializer that delegates to a designated initializer
lazyStored property initialised at most once, on first access
dynamicDispatched through the Objective-C runtime; requires @objc
optionalProtocol member a conforming type need not implement; @objc protocols only
weakNon-owning reference; must be an optional var of class type
unownedNon-owning, non-optional reference; traps if used after deallocation
unowned(unsafe)As above with no check; undefined behaviour after deallocation
mutating / nonmutatingWhether a value-type method may modify self
nonisolatedActor member that is not isolated to the actor
indirectEnumeration case stored behind a reference, permitting recursion
infix / prefix / postfixFixity of an operator declaration

Source: The Swift Programming Language, Declarations → Declaration Modifiers.

Back to top

Operators and precedence

Swift has no fixed operator table in the grammar. Operators are library declarations that name a precedence group, and precedence groups declare their relations to one another with higherThan and lowerThan. The hierarchy need only be partially ordered, so two groups may have no defined relation, in which case their operators cannot appear adjacent without parentheses.

The eleven precedence groups used by the standard library.

Precedence groupAssociativityStandard library operators
BitwiseShiftPrecedencenone<< >> &<< &>>
MultiplicationPrecedenceleft* / % & &*
AdditionPrecedenceleft+ - | ^ &+ &-
RangeFormationPrecedencenone..< ...
CastingPrecedenceleftis as as? as!
NilCoalescingPrecedenceright??
ComparisonPrecedencenone< <= > >= == != === !== ~= and the pointwise . forms
LogicalConjunctionPrecedenceleft&& .&
LogicalDisjunctionPrecedenceleft|| .| .^
TernaryPrecedenceright? :
AssignmentPrecedenceright= and the compound forms += -= *= /= %= <<= >>= &= |= ^= and the &-prefixed wrapping forms

Source: Apple Developer, Operator Declarations. Listed in decreasing order of precedence. Prefix operators (! ~ + - ..< ...) and postfix ... bind more tightly than any infix operator.

// Declaring a new operator: fixity declaration, precedence group, implementation.
infix operator |>: ForwardPipePrecedence

precedencegroup ForwardPipePrecedence {
    associativity: left
    higherThan: AssignmentPrecedence
    lowerThan: TernaryPrecedence
}

func |> <A, B>(value: A, transform: (A) -> B) -> B { transform(value) }

let shortNames = names |> { $0.filter { $0.count < 6 } }

// Overloading an existing operator for your own type.
extension Rectangle {
    static func * (lhs: Rectangle, rhs: Double) -> Rectangle {
        Rectangle(width: lhs.width * rhs, height: lhs.height * rhs)
    }
}
Convention. The API design guidelines advise against inventing operators whose meaning is not established by mathematical or domain convention. A named method is discoverable, searchable, and documentable; a custom operator is none of those.

Back to top

Standard library map

The standard library is written in Swift and is available to every program without an import. It sits on a C++ runtime that implements the dynamic parts of the language — type metadata, generic instantiation, dynamic casting, reflection, and reference counting — and, on Apple platforms, on SDK overlays that adapt Objective-C frameworks to Swift conventions.

Fundamental types

Int, UInt, Double, Float, Bool, String, Character, Optional, Result.

Collections

Array, Dictionary, Set, Range, Slice, and the lazy and reversed wrappers — all value types with copy-on-write.

Concurrency

Task, TaskGroup, AsyncSequence, AsyncStream, Sendable, Clock, Duration.

Low level

UnsafePointer family, Span, RawSpan, MemoryLayout, ManagedBuffer, isKnownUniquelyReferenced.

The protocols a type most often adopts, and what each buys.

ProtocolRequirementAutomatic conformanceWhat it unlocks
Equatable==Synthesised when all members conformPrerequisite for Hashable and most algorithms
Hashablehash(into:)Synthesised when all members conformKeys of Dictionary, elements of Set
Comparable<Synthesised for enums without associated valuessorted(), min(), ranges
SequencemakeIterator()for-in, map, filter
CollectionstartIndex, endIndex, subscriptMulti-pass traversal and indices
Codableinit(from:), encode(to:)Synthesised for most typesJSON and property-list serialisation
SendableNone — a marker protocolInferred for value types of Sendable membersCrossing isolation boundaries
IdentifiableidDiffable collections, SwiftUI lists
CaseIterableallCasesSynthesised for enums without associated valuesEnumerating a closed set
CustomStringConvertibledescriptionString(describing:) and interpolation
ErrorNone — a marker protocolAnything thrown
CopyableNone — implicitImplicit on every typeSuppress with ~Copyable

Sources: Apple Developer standard library reference and the Protocols chapter. “Synthesised” means the compiler writes the implementation when the declaration lists the conformance.

Beyond the standard library, a set of packages maintained by the Swift project is treated as quasi-standard: swift-collections (deque, ordered set and dictionary, heap), swift-algorithms, swift-numerics, swift-argument-parser, swift-log, swift-nio, and swift-syntax. The Standard Library Preview package additionally vends accepted evolution proposals as standalone modules before they ship in the library itself.

Back to top

API design guidelines

Swift's naming conventions are published as normative guidelines by the Swift project, and the standard library follows them exactly. They are grammatical rather than typographical: the aim is that a call site reads as an English phrase, which is why argument labels exist as a separate concept from parameter names.

The rules that decide most naming arguments.

GuidelineWhat it means
Clarity over brevityClarity at the point of use is the goal; brevity is a side effect of the type system, never an aim
Document every declarationWrite a doc comment for every declaration; difficulty describing an API is evidence of a design problem
Omit needless wordsEvery word should convey salient information at the use site
Name by role, not by typeName variables and parameters for what they are used for, not their type
Compensate for weak type informationAdd a noun describing the role when the parameter type is Any-like
Side effects decide the part of speechNo side effects reads as a noun phrase (x.distance(to: y)); side effects read as an imperative verb (x.sort())
Boolean members read as assertionsx.isEmpty, line1.intersects(line2)
Protocol namesWhat something is reads as a noun (Collection); a capability takes “able”, “ible”, or “ing” (Equatable, ProgressReporting)
Label prepositional phrasesWhen an argument is part of a prepositional phrase, the label starts at the preposition: x.removeBoxes(havingLength: 12)
Omit the label on value-preserving conversionsInt64(someUInt32), not Int64(value: ...)
Use terms of art correctlyPrefer the common word unless a technical term is genuinely more precise; then use it strictly

Source: Swift.org, API Design Guidelines. Reproduced in condensed form; the full document includes worked counter-examples for each rule.

Naming mutating and nonmutating method pairs.

CaseMutatingNonmutatingRule
Mutating verbx.sort()z = x.sorted()Append “ed” for the nonmutating form
Verb with a direct objects.stripNewlines()t.strippingNewlines()Append “ing” when “ed” is ungrammatical
Noun operationy.formUnion(z)x = y.union(z)Noun names the nonmutating form; prefix “form” for the mutating one

Mutating and nonmutating pairs must be named consistently, so that a reader can predict one from the other.

// Reads as a phrase at the point of use.
let foreground = Color(red: 32, green: 64, blue: 128)
let newPart = factory.makeWidget(gears: 42, spindles: 14)
employees.remove(at: x)                  // Not remove(x) - ambiguous with remove(element)
allViews.remove(cancelButton)            // No label: the argument is the thing being removed

// Grammatical continuity forced into the first argument reads worse, not better.
// let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)

// Documentation comment: a summary fragment first, then parameters and returns.
/// Returns a view of `self` containing the same elements in reverse order.
///
/// - Parameter preservingIndices: Whether index positions are retained.
/// - Returns: A lazily evaluated reversed collection.
/// - Complexity: O(1).
func reversed(preservingIndices: Bool = false) -> ReverseCollection<Self>

Back to top

Documentation comments and DocC

Documentation comments use /// or /** */ and are written in Swift's dialect of Markdown. DocC, the documentation compiler in the toolchain, reads them together with standalone article files and tutorial files to produce a documentation archive that can be hosted statically or read inside Xcode. Because the doc comments are compiled rather than scraped, a reference to a symbol that no longer exists is a build warning.

/// A logger that records temperature measurements for one location.
///
/// Create a logger with an initial measurement, then record further readings
/// with ``update(with:)``. The maximum is maintained incrementally:
///
/// ```swift
/// let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
/// await logger.update(with: 31)
/// ```
///
/// - Note: Access from outside the actor is asynchronous.
/// - SeeAlso: ``Measurement``
public actor TemperatureLogger { }

The callouts DocC recognises include - Parameter, - Parameters, - Returns, - Throws, - Complexity, - Precondition, - Note, - Warning, and - SeeAlso. Double-backtick syntax (``symbol``) creates a checked link to another symbol. Documentation is built with swift package generate-documentation and previewed with swift package --disable-sandbox preview-documentation.

Back to top

Compilation and code generation

Swift does not go straight from source to LLVM IR. It introduces its own intermediate representation, SIL (Swift Intermediate Language), which is high-level enough to still know about generics, protocol conformances, ownership, and reference counting. Most of what distinguishes Swift's optimiser from a generic LLVM front end happens at that level: generic specialisation, devirtualisation of protocol witnesses, ARC traffic elimination, copy-on-write and exclusivity checking, and closure specialisation.

Parse SwiftSyntax → AST Sema type check, infer Macro expansion plugin process SIL generic specialisation devirtualisation ARC optimisation exclusivity, CoW LLVM IR target-independent Machine code .o, .swiftmodule
Figure 1. The swiftc pipeline. Macro plugins run as separate processes during type checking; the Swift-specific optimisations run on SIL, before LLVM sees the program. Diagram: Programming Language Atlas, after the Swift compiler architecture documentation.

Why the optimisation level matters more than in C

An unoptimised Swift build leaves generic functions unspecialised, protocol calls indirect through witness tables, and every retain and release in place. Specialisation and ARC elimination recover most of that, so the gap between -Onone and -O is substantially wider than the equivalent gap in C. Benchmarking a debug build tells you very little.

Module granularity

By default each file is compiled separately, so cross-file inlining and specialisation cannot happen. Whole-module optimisation (-wmo, the default for release builds in SwiftPM and Xcode) compiles the module as one unit. Across module boundaries, specialisation requires the body to be visible, which is what @inlinable provides — at the cost of freezing that body into every client.

Resilience

A library built with -enable-library-evolution accesses stored properties indirectly and calls through a dispatch thunk, so it can add members without breaking compiled clients. That indirection is the price of binary stability, and @frozen is how a library opts a specific type out of it.

The seven costs that show up most often in Swift profiling.

CostWhat it isUsual remedy
Existential (any P)Boxed if larger than three words; dynamic dispatchUse some P or a generic parameter where the type is uniform
Unspecialised genericsIndirect calls and opaque layoutWhole-module optimisation, or @inlinable across modules
Retain/release trafficAtomic count updates on every reference copyValue types, borrowing parameters, unowned where lifetimes allow
Copy-on-write copiesA full buffer copy on mutation of a shared valuereserveCapacity, in-place mutation through subscript rather than get-modify-set
String indexingO(n) index arithmetic over grapheme clustersIterate rather than index; use utf8 when byte offsets are what you actually need
Dynamic castsRuntime metadata lookupDesign out as? on hot paths
Objective-C bridgingBoxing and unboxing at every crossingKeep hot loops on the Swift side of the boundary

Sources: Swift compiler documentation and the performance discussions in the Swift forums. Every row is a trade-off the language makes deliberately, not a defect.

Swift sourceone language mode per module; macros already expandedRaw SILdefinite initialisation, exclusivity diagnosticsCanonical SILARC optimisation, generic specialisation, inliningLLVM IRtarget-independent optimisation, then instruction selectionObject codelinked against the runtime and standard library
Figure 2. What each lowering step is responsible for. SIL is the level that distinguishes Swift from a front end that emits LLVM IR directly: reference counting, generic specialisation, exclusivity checking and definite initialisation are all decided here, where the compiler still knows about Swift's semantics.

Back to top

Swift Evolution

Every change to the language goes through a public process. A pitch is posted to the Swift forums for informal discussion; if it gains traction, it is written up as a proposal in the swiftlang/swift-evolution repository with an SE-NNNN number and a reference implementation. A language steering group schedules a review period, typically one to two weeks, and then publishes an acceptance, rejection, or return-for-revision with written rationale.

Pitch

Forum thread. Motivation and rough design; most proposals change substantially at this stage or stop here.

Proposal

SE-NNNN document: motivation, proposed solution, detailed design, source-compatibility impact, alternatives considered.

Review

Scheduled and announced. Anyone may respond; the review manager summarises.

Decision

Steering group accepts, rejects, or returns for revision, with published rationale. Accepted work then ships behind a flag or in a language mode.

The process has a specific consequence for developers: a language change almost never arrives unannounced. A behaviour that will be the default in a future language mode is available first as an upcoming feature flag, so a codebase can adopt it, and be diagnosed against it, one release before it becomes mandatory. The Release model section of the language article describes how those flags combine with language modes.

Governance is distributed across workgroups — language steering, core team, and topic-specific groups for the platform ports (Android, Windows), the server ecosystem, C++ interoperability, documentation, and website. Each publishes its charter and meeting notes on swift.org.

Back to top

Sources

  • Apple Inc. and the Swift project — The Swift Programming Language (6.4 beta edition), docs.swift.org/swift-book: Attributes, Declarations, Expressions, Statements, and Summary of the Grammar.
  • Swift.org — API Design Guidelines, reproduced here in condensed form.
  • Swift.org — Using C++ from Swift, Standard Library, Server, and Getting Started pages.
  • Swift.org — Migrating to Swift 6, the concurrency migration guide.
  • Apple Developer — developer.apple.com/documentation/swift, including Operator Declarations, the source for the precedence-group table.
  • swiftlang/swift-package-managerPackageDescription API reference for tools version 6.
  • swiftlang/swift-evolution — proposal index and process documentation.

Code examples are original or adapted from the cited official documentation. Where a table condenses a longer source document, the caption names it so the full text can be consulted.

Back to top