Overview of attributes (declaration|type) in the Swift programming language
Highlight: System Programming Interfaces (SP), an experimental attribute of Swift
1. Marco Eidinger, Nov 12th 2022
A tour through Swift attributes
Highlight: System Programming Interfaces (experimental)
2. About me
https://blog.eidinger.info/
• Developing iOS apps and frameworks
for over a decade at my day job.
• Personally, I contribute to the iOS
community with open-source tools
like SwiftPlantUML and
XCSnippetsApp.
• I love to write and share my
programming knowledge on my blog
SwiftyTech (+ 100 articles).
• Find me on on GitHub and Twitter as
@MarcoEidinger.
4. Attributes
Non-exclusive list of o
ffi
cial attributes
@autoclosure
@escaping
@frozen
@main
@globalActor
@inlinable
@available
@Sendable
@preconcurrency
@warn_unqualified_access
@testable
@propertyWrapper
@dynamicMemberLookup
@nonobjc
@objc
@objcMembers
5. We use Swift attributes all the time
import SwiftUI
struct ExampleAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
6. We use Swift attributes all the time
import SwiftUI
@main
struct ExampleAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
7. SwiftUI framework
@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension App {
/// Initializes and runs the app.
///
/// If you precede your ``SwiftUI/App`` conformer's declaration with the
/// @main attribute, the system calls the conformer's `main()`
/// method to launch the app.
/// SwiftUI provides a default implementation of the method
/// that manages the launch process in a platform-appropriate way.
@MainActor public static func main()
}
9. Two kinds of attributes
apply to declarations vs. types
@frozen public enum Exhaustive {}
import SwiftUI
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
var body: Content {
self.build()
}
}
10. Attributes are essential building blocks
Example: SwiftUI
import SwiftUI
struct LocalizedView: View {
var counter = 0
var body: some View {
Button("Increase counter") {
counter += 1
}
}
}
11. Attributes are essential building blocks
Example: SwiftUI
import SwiftUI
struct LocalizedView: View {
@State var counter = 0
var body: some View {
Button("Increase counter") {
counter += 1
}
}
}
12. Attributes are essential building blocks
Example: SwiftUI
import SwiftUI
struct LocalizedView: View {
@State var counter = 0
var body: some View {
Button("Increase counter") {
counter += 1
}
}
}
@frozen @propertyWrapper public struct State<Value> : DynamicProperty {…}
13. Attributes are essential building blocks
Example: Concurrency
@MainActor class ViewModel: ObservableObject {}
14. Attributes are essential building blocks
Example: Concurrency
@globalActor final public actor MainActor : GlobalActor {…}
@MainActor class ViewModel: ObservableObject {}
15. Attributes are essential building blocks
Example: Concurrency
@globalActor final public actor MainActor : GlobalActor {…}
@MainActor class ViewModel: ObservableObject {}
extension MainActor {
public static func run<T>(
resultType: T.Type = T.self,
body: @MainActor @Sendable () throws -> T) async rethrows -> T where T : Sendable
}
17. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
18. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
@resultBuilder
19. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
• Use @resultBuilder to create cool DSLs.
20. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
• Use @resultBuilder to create cool DSLs.
@propertyWrappers
21. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
• Use @resultBuilder to create cool DSLs.
• Use @propertyWrappers to create reusable property implementation
patterns. Property wrappers in the wild.
22. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
• Use @resultBuilder to create cool DSLs.
• Use @propertyWrappers to create reusable property implementation
patterns. Property wrappers in the wild.
@_alwaysEmitIntoClient
23. Interesting use cases
Extensively used in SwiftUI (but not limited to SwiftUI)
• Use @warn_unquali
fi
ed_access to make your SwiftUI view modi
fi
ers safer.
• Use @resultBuilder to create cool DSLs.
• Use @propertyWrappers to create reusable property implementation
patterns. Property wrappers in the wild.
• SwiftUI uses @_alwaysEmitIntoClient to back port new features
25. Code is better than documentation
• Swift 5.7
• https://github.com/apple/swift/blob/release/5.7/include/swift/AST/Attr.def
• Swift 5.8 and beyond
• Code Ownership of Swift Attributes to swift-syntax
• Replace Attr.def with a gyb
fi
le that reads from swift-syntax to automatically
generate the attribute nodes.
• https://github.com/apple/swift-syntax/blob/main/gyb_syntax_support/
AttributeKinds.py
26. Definition of Declaration Attributes
https://github.com/apple/swift-syntax/blob/main/gyb_syntax_support/AttributeKinds.py
29. Warning: Apple discourages
using underscored attributes
those semantics are subject to change and most likely need to go through the Swift evolution process before being stabilized.
30. Early adoption still possible
Successful transition from experimental to proper language feature
@resultBuilder
@_functionBuilder
Swift 5.1 Swift 5.4
33. System Programming Interface
Experimental @_spi and related attributes
Attribute
Introduced
in
@_spi Swift 5.3
@_spi_available(platform, version) Swift 5.7
@_spiOnly master (~ Swift 5.8)
35. Shopping.swiftinterfaces
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.127.4
clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx10.13 -enable-objc-interop
-enable-library-evolution -swift-version 5 -Onone -module-name Shopping
import Swift
import _Concurrency
public struct ShoppingCartItem {
public init()
}
public struct ShoppingCart {
public init()
public func payCash()
}
36. Shopping.private.swiftinterfaces
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.127.4
clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx10.13 -enable-objc-interop
-enable-library-evolution -swift-version 5 -Onone -module-name Shopping
import Swift
import _Concurrency
public struct ShoppingCartItem {
public init()
}
public struct ShoppingCart {
public init()
public func payCash()
@_spi(PayPal) public func payWithPayPal()
}
37. @_spi_available(platform, version)
// Module "Shopping"
public struct ShoppingCart {
public init() {}
@_spi_available(watchOS 9, *)
@available(tvOS, unavailable)
public private(set) var items = [ShoppingCartItem]()
public func payCash() {}
@_spi(PayPal) public func payWithPayPal() {}
@_spi(Bitcoin) public func payWithBitcoin() {}
}
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7
// swift-module-flags: -target arm64-apple-macosx10
version 5 -Onone -module-name Shopping
import Swift
import _Concurrency
public struct ShoppingCartItem {
public init()
}
public struct ShoppingCart {
public init()
@available(watchOS, unavailable)
@available(tvOS, unavailable)
public var items: [Shopping.ShoppingCartItem] {
get
}
public func payCash()
}