この記事の要点
- WWDC22 で紹介された Swift エコシステムの動きを、Swift.org Blog の著者陣が「注目した点」としてまとめたハイライト記事です。この1年で Swift 5.6(2022年3月リリース)と Swift 5.7(当時 Xcode 14 ベータに同梱)の2つの大型アップデートがあり、その内容を横断的に取り上げています。
- コミュニティ面では、新しいワークグループ(Website、Swift and C++ interoperability、Language Workgroup)の発足、Swift Mentorship Program の継続、Swift.org Webサイトのオープンソース化、Swift-DocC のオープンソース化と機能拡張が紹介されています。
- 言語面では、
if letの短縮構文、複数文クロージャの型推論、正規表現(regex リテラルと RegexBuilder)、ジェネリクスとプロトコル(primary associated types、some/any)、並行処理(distributed actor、Async Algorithms、Clock/Instant/Duration)といった、Swift 5.7 を中心とする多くの新機能が要点として挙げられています。
この記事は公式のWWDCハイライトなので、ここでは Swift 利用者が押さえておくとよい注目トピックを選んで整理し、Swift Digest 内の関連ダイジェストへの導線を示します。網羅的な内容は元記事を参照してください。
注目トピック
コミュニティとツールの動き
Swift コミュニティの取り組みが広がり、特定領域に注力する新しいワークグループが発足しました。Swift.org Webサイトの進化を導く Website Workgroup、2言語間の相互運用を進める Swift and C++ interoperability ワークグループ、言語と標準ライブラリを統括する Language Workgroup です。2021年に発表された Swift Mentorship Program はさらに1年延長され、DocC・C++ 相互運用・Swift Webサイトといったテーマが追加されました。また Swift.org Webサイト自体がオープンソース化され、コミュニティからのコントリビューションを受け付けるようになっています。
Swift フレームワーク・パッケージ向けのドキュメントコンパイラ Swift-DocC もオープンソース化され、アプリプロジェクトのサポートや Objective-C / C API ドキュメントのサポートが追加されました。
Swift Package Manager の更新
Swift Package Manager にも重要なアップデートがありました。
- TOFU 検証: Swift 5.6 以降、Swift Package Manager は trust on first use(TOFU)検証を行います。パッケージを最初にダウンロードした時点でフィンガープリントを記録し、以降のダウンロードでフィンガープリントが異なるとエラーを報告するため、パッケージのセキュリティが向上します。
- module aliasing: Swift 5.7 では、同名のモジュールを複数のパッケージから利用する際の問題を避けられるようになりました。パッケージを定義する側の外からモジュールに別名を付けられます(SE-0339)。
- plugin: 新しい
PackagePluginAPI により、ソースコード生成やリリース作業の自動化を行うカスタムプラグイン(build tool plugin / custom command plugin)を Swift で記述できるようになりました(SE-0325)。
言語機能のアップデート
Swift 5.7 では、細かな構文改善から大きなジェネリクス・並行処理の更新まで、幅広い言語機能が追加されました。元記事ではニュージーランドの「Bird of the Year」を題材にしたコード例で紹介されています。
if let の短縮構文(SE-0345): if let / guard let / while let でオプショナルをアンラップする際、右辺が同名の変数なら省略できます。
var startDate: Date?
if let startDate {
print("Competition starts on \(startDate.formatted())")
}
複数文クロージャの型推論: if else や do catch などの制御構文を含むクロージャでも、戻り値の型を手動で指定する必要がなくなりました。
let participants = ["Kororā", "Weka", "Pekapeka-tou-roa"]
let introductions = participants.map {
if $0.hasPrefix("Pekapeka") {
return "\($0) is a mammal"
} else {
return "\($0) is a bird"
}
}
正規表現: regex リテラル(SE-0354)と RegexBuilder ライブラリ(SE-0351)により、強く型付けされたキャプチャを伴う文字列処理が可能になりました。名前付きキャプチャを結果から取り出せます。
let intent = "I vote for Pūkeko and Kea"
let regex = /I vote for (?<bird1>.+?) and (?<bird2>.+?)/
if let votes = try? regex.wholeMatch(in: intent) {
print("Your first choice is \(votes.bird1)")
print("Your second choice is \(votes.bird2)")
}
RegexBuilder を使うと、SwiftUI 風の宣言的な記述で正規表現を組み立てられます。
let word = OneOrMore(.word)
let regex = Regex {
"I vote for "
Capture { word }
" and "
Capture { word }
}
if let votes = try? regex.wholeMatch(in: intent) {
let (_, bird1, bird2) = votes.output
print("Your first choice is \(bird1)")
print("Your second choice is \(bird2)")
}
ジェネリクスとプロトコル: プロトコルが primary associated types をサポートするようになり、プロトコル名の隣の山かっこで指定できます(SE-0346)。
protocol Contestant<Habitat> {
associatedtype Habitat: Territory
associatedtype Food
var home: Habitat { get set }
var favoriteFood: Food { get set }
var name: String { get }
}
これにより、山かっこ構文で primary associated type を特定の型に制約できます。また、パラメータの型に some を使えるようになり(SE-0341)、ジェネリックパラメータが1か所でしか使われない場合は、関数にジェネリック制約を付けずに some で書けます。
func fundConservationEfforts(for animal: some Contestant) {
establishProtectedAreas(in: animal.home)
startIntensiveMonitoring(of: animal)
}
func fundReforestation(for animal: some Contestant<Forest>) {
scheduleTreePlanting(in: animal.home)
}
existential 型にも大きな改善があり、any キーワードで existential 型を使う箇所を明示できるようになりました(SE-0335)。Self や associatedtype 要件を持つプロトコルでも existential 型として扱えるようになり(SE-0309)、コレクションに入れたり変数や引数の型として使えます。
let contestants: [any Contestant] = [
brownKiwi, ruru, whio
]
for contestant in contestants {
fundConservationEfforts(for: contestant)
}
なお、any Contestant<Forest> のように existential 型へ制約を付ける機能は SE-0353 で導入されました。
並行処理: この年の並行処理アップデートは前年の変更を土台に、データ競合安全性に重点を置いています。
- distributed actor: アクターによる isolation の考え方を分散システムへ広げる distributed actor が導入されました(isolation は SE-0336、ランタイムは SE-0344)。オープンソースの Distributed Actors ライブラリは、サーバーサイドのクラスタ型分散システムを Swift で構築するための完全なソリューションを提供します。
- Async Algorithms:
AsyncSequenceを扱うための Async Algorithms パッケージが登場し、debounce・throttle・merge・zipなど、自前では実装が難しいアルゴリズムを提供します。 - 時間の扱い: clock・instant・duration という3つのコンポーネントからなる、時間を扱う標準的な API が追加されました(SE-0329)。並行処理のタスクとよく統合されています。
func announceWinner(_ winner: some Contestant) async throws {
try await Task.sleep(
until: .now + .seconds(10),
tolerance: .seconds(1),
clock: .suspending
)
print("The winner is \(winner.name)!")
}
このほか、パフォーマンス最適化、アクターの優先度付けと優先度逆転の回避、Instruments の Swift Concurrency テンプレートなど、並行処理まわりの多くの強化が行われています。さらに、ビルドの並列化による高速化、where 句やプロトコルを含む関数シグネチャの型チェック高速化、実行時のプロトコル適合チェックの最適化、標準ライブラリのサイズ削減と Linux 向けツールチェーン配布の整備など、多岐にわたる改善が紹介されています。
Swift Digestで詳しく読むべき項目
WWDC22 で取り上げられた主な言語機能は、それぞれ Swift Evolution Proposal のダイジェストがあります。
if let短縮構文の詳細は SE-0345 を参照してください。- ジェネリクス・プロトコルまわりは、primary associated types の SE-0346、opaque parameter(
some)の SE-0341、existentialanyの SE-0335、すべてのプロトコルでの existential 解放 SE-0309、制約付き existential 型 SE-0353 で扱っています。 - 正規表現は、regex リテラルの SE-0354、
Regex型の概要 SE-0350、RegexBuilder DSL の SE-0351 を参照してください。 - 並行処理は、
Clock/Instant/Durationの SE-0329、distributed actor の SE-0336 と SE-0344 を参照してください。 - Swift Package Manager の module aliasing は SE-0339、追加の Package Plugin API は SE-0325 で扱っています。
- コミュニティ関連の動きは、Language Workgroup の発足と Swift.org Webサイトのオープンソース化のダイジェストにまとめています。