Attributes and Compiler Control

This section documents the Swift 6 language mode as shipped by Swift 6.3, as published in The Swift Programming Language at docs.swift.org, which is the reference these pages are written and verified against. 6.4-beta-only features are always flagged as such — never presented as baseline.

This content was generated with the assistance of AI and should be verified against docs.swift.org before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Attributes attach compiler-visible metadata to a declaration or a type; declaration modifiers (final, static, override, …​) and compiler control statements (#if, #warning, …​) round out the language’s remaining ways of talking to the compiler rather than to the running program.

Declaration Attributes

@available(iOS 17, macOS 14, *)
func modernAPI() { }

@available(*, deprecated, renamed: "modernAPI()", message: "use modernAPI() instead")
func legacyAPI() { }

@discardableResult
func logAndReturn(_ value: Int) -> Int {
    print(value)
    return value      // callers may ignore this return value with no warning, thanks to @discardableResult
}

@main
struct EntryPoint {
    static func main() { print("started") }
}

@available(…​) states the platforms/versions a declaration requires, or marks it deprecated/unavailable/ renamed:, and is checked at every call site; @discardableResult silences the "result unused" warning a non-Void-returning function would otherwise get when its return value is ignored; @main designates the program’s entry-point type, replacing a top-level main.swift file.

@frozen
public struct Point {                 // library-evolution promise: no new stored properties will ever be added
    public var x, y: Double
}

@inlinable
public func distance(_ a: Point, _ b: Point) -> Double {
    ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)).squareRoot()
}

@usableFromInline
internal func helper() -> Int { 42 }   // internal, but callable from an @inlinable function in the same module

@backDeployed(before: iOS 17)
public func newConvenienceAPI() { }    // callable on OS versions older than where it actually shipped

@frozen and @inlinable are library-evolution attributes for binary frameworks: @frozen promises a struct/ enum’s layout won’t change in a future library version (letting clients store it inline rather than through an indirection), and @inlinable exposes a function’s body for cross-module inlining, which in turn requires any internal symbol it touches to be marked @usableFromInline. @backDeployed(before:) lets a newer API run on OS versions that shipped before it, by embedding a compatibility shim in the calling binary.

@objc
class LegacyBridge: NSObject {
    @objc(displayNameForUser:)
    func displayName(for user: String) -> String { user.capitalized }
}

@objcMembers
class AllExposed: NSObject {           // every member below is implicitly @objc, no need to annotate each one
    var count = 0
    func increment() { count += 1 }
}

class PlainSwift {
    @nonobjc
    func swiftOnly() { }               // opts one member out of an otherwise @objc-exposed type
}

@preconcurrency
import SomeUnauditedObjCFramework      // suppresses Sendable/isolation warnings for this import only

@testable import MyAppModule           // exposes `internal` declarations to a test target

@objc/@objcMembers/@nonobjc control Objective-C runtime visibility — see Interoperability with C, Objective-C and C++ for the bridging this enables. @preconcurrency on an import relaxes Swift 6’s strict concurrency checking for a module that predates Sendable auditing, without disabling it project-wide — see Actors, Isolation and Sendable. @testable import is how a test target reaches a module’s internal (but not private) declarations, covered again in Testing.

@dynamicMemberLookup
struct Proxy { subscript(dynamicMember member: String) -> String { member } }

@propertyWrapper
struct Clamped {
    var wrappedValue: Int
    init(wrappedValue: Int) { self.wrappedValue = wrappedValue }
}

@resultBuilder
struct ArrayBuilder<T> {
    static func buildBlock(_ items: T...) -> [T] { items }
}

@globalActor
actor SettingsActor {
    static let shared = SettingsActor()
}

func apply(@autoclosure _ condition: () -> Bool, onFailure action: @escaping @Sendable () -> Void) { }

@dynamicMemberLookup, @propertyWrapper and @resultBuilder are covered in full in Key Paths and Dynamic Member Lookup, Properties and Result Builders respectively; @globalActor defines a new global actor (like the built-in @MainActor) usable to annotate other declarations, per Actors, Isolation and Sendable. Type attributes — @escaping (a closure parameter that may outlive the call), @autoclosure (a parameter written as an expression, auto-wrapped in a closure), @Sendable (a closure safely shared across concurrency domains) and @convention (a function value’s calling convention: swift, block, or c) — are covered where each is most relevant: Closures for the first three, Interoperability with C, Objective-C and C++ for @convention.

@unknown default, Declaration Modifiers and Compiler Control

enum Direction { case north, south, east, west }

func describe(_ direction: Direction) -> String {
    switch direction {
    case .north: "N"
    case .south: "S"
    case .east, .west: "E/W"
    @unknown default: "unrecognized direction added in a newer library version"
    }
}

@unknown default marks a switch case that should only ever run if a non-frozen enum (typically from a binary-distributed library) gains a new case in a future version the code wasn’t compiled against — unlike a plain default, the compiler still warns if the switch doesn’t otherwise cover every case currently known, so adding a genuinely new case to the enum today is caught at the call site rather than silently swallowed.

class Base {
    final func cannotBeOverridden() { }
    class func classMethod() { }               // dynamically dispatched, overridable by subclasses
    static func staticMethod() { }              // like class func, but cannot itself be overridden
    required init() { }                         // every subclass must provide this initializer
    lazy var expensive: [Int] = computeOnce()
    weak var delegate: AnyObject?
    unowned let owner: Base
    indirect enum Tree { case node(Tree, Tree) }
    private(set) var readOnlyOutside = 0
    dynamic func objcDispatched() { }           // forces Objective-C message-send dispatch, e.g. for KVO/swizzling
    nonisolated func notActorConfined() { }
    mutating func mutatingOnStruct() { }
    nonmutating func doesNotMutate() { }
}

Declaration modifiers each state a fact about how a declaration participates in inheritance, memory management, concurrency isolation, or dispatch: final forbids overriding; static/class distinguish non-overridable vs. overridable type-level members; override/required govern subclass obligations; lazy defers a stored property’s initial value until first access; weak/unowned (see Automatic Reference Counting); indirect lets an enum case hold itself recursively; optional/dynamic matter for @objc protocol members and runtime dispatch; nonisolated/mutating/nonmutating govern actor isolation and value-type self-mutation (see Actors, Isolation and Sendable and Methods and Subscripts).

#if os(macOS) || os(Linux)
import Foundation
#endif

#if swift(>=6.0) && compiler(>=6.0)
let usesTypedThrows = true
#endif

#if canImport(UIKit)
import UIKit
#endif

#if hasFeature(StrictConcurrency)
// code that only compiles under a specific upcoming-feature flag
#endif

#warning("this branch still uses the deprecated API")
#if DEBUG
#error("DEBUG builds must not ship")
#endif

func trace(file: String = #file, line: Int = #line, function: String = #function) {
    print("\(function) at \(file):\(line)")
}

if #available(iOS 17, *) {
    modernAPI()
} else if #unavailable(macOS 14) {
    // fallback path for platforms this code doesn't support
}

Conditional compilation (#if/#elseif/#else/#endif) tests platform (os(), arch()), language/compiler version (swift(), compiler()), module availability (canImport()), or an upcoming-feature flag (hasFeature()), and is resolved entirely before type-checking — an unreachable branch’s code isn’t even parsed against the current platform. #warning/#error emit a diagnostic (the latter halting compilation) at a specific point in the source; #file/#line/#function (and #filePath/#column) capture the call site’s source location when used as a default parameter value, which is how Swift Testing’s #expect reports failures at the exact line that failed rather than inside its own implementation. #available/#unavailable are runtime platform-version checks — unlike @available, which the compiler checks statically, these guard a branch of code that runs conditionally depending on the actual OS version at execution time.

See Also