☄️

Swift 6 に備える - 今後の機能(Upcoming Feature)の段階的適用 編

2024/02/29に公開

チートシート

Swift 6 がやってくる

記事執筆時点では Swift 5.9 までがリリース済み、これから Xcode 15.3 とともに Swift 5.10 がリリースされようとしています。それではその次は 5.11…… と思われましたが、Apple の @hollyborla 氏によって「Swift 5.10 の次は Swift 6 となる」ことが言及されています。

Swift 5 の間、さまざまな機能が Swift には追加されてきました。それらの中には影響範囲が大きいとみられるものも含まれており、「この機能のうちの◯◯までは Swift 5 で、××は Swift 6 で有効になる」というようなものがいくつか存在します("××" が影響が大きいとされるものであることが多い)。

ここでの「影響が大きい」とは、コード自体はそのままで Swift の(コンパイラの)バージョンを上げた際に、これまでとは違う解釈となって挙動が変わってしまったり、そもそもコンパイルエラーとなってしまったりするような状態になることを指します。

これでは、なかなか Swift 6 へバージョンアップするのを躊躇してしまいそうです。

Swift 6 以降で有効になる機能を自分で選んでちょっとずつ有効にできる

そこで、Swift 5.8 では「将来追加予定の言語改善への段階的な適用[1]」を行うためのコンパイラフラグ(-enable-upcoming-feature)などが追加されました(SE-0362)。これを用いることで、「影響が大きいとされる Swift 6 以降での変更」を Swift 5.8 以降のプロジェクトにおいて先取りすることができます。

Xcode プロジェクトの場合

Xcode プロジェクトの場合、「将来追加予定の言語改善への段階的な適用」を行いたいターゲットの「Build Settings」にある、「Swift Compiler - Custom Flags」>「Other Swift Flags(OTHER_SWIFT_FLAGS)」に -enable-upcoming-feature 機能名 を追加します(Xcode 14.3 以降である必要があります)。

Swift Package の場合

Swift Package の場合、「将来追加予定の言語改善への段階的な適用」を行うには、ターゲットの swiftSettings で「SwiftSetting.enableUpcomingFeature(_:_:)」を用います(swift-tools-version は 5.8 以降である必要があります)。

先取りして有効にできる Swift 6 の機能一覧チートシート

しかし、この enableUpcomingFeature(_:_:) に渡す文字列をいちいち定義ファイル[2]から探してくるのは面倒で、また typo などで実は有効になっていなかった!というのも悲しくなります。

そこで、Package.swift にコピペで使えるチートシートを用意しました。

そのチートシートの内容をコピペすると、以下のように補完を効かせて「将来追加予定の言語改善への段階的な適用」を行うことができます。

独断と偏見を含んだ「先取りして有効にできる Swift 6 の機能」の見解

先述のチートシートに含まれている、記事執筆時点(Swift 5.10)までで使用できる「先取りして有効にできる Swift 6 の機能」について、個人的な見解を含んだ表を以下に示します。

機能名 プロポーザル デフォルトで有効になる予定のバージョン 新規のプロジェクトで有効にするべきか 既存のプロジェクトで有効にする際の難易度 メモ
ForwardTrailingClosures (SwiftPM 5.8+) SE-0286 Swift 6 普通〜やや難 クロージャが末尾に複数あるような関数に影響が出る場合があるので注意
ExistentialAny (SwiftPM 5.8+) SE-0335 Swift 7 普通〜難 解説記事を公開済み
BareSlashRegexLiterals (SwiftPM 5.8+) SE-0354 Swift 6 普通 -
ConciseMagicFile (SwiftPM 5.8+) SE-0274 Swift 6 やや易 積極的に使いたい / 問題がある場合は #file#filePath へ切り替えることで対応可能
ImportObjcForwardDeclarations (SwiftPM 5.9+) SE-0384 Swift 6 Objective-C の利用具合による -
DisableOutwardActorInference (SwiftPM 5.9+) SE-0401 Swift 6 やや易〜やや難 -strict-concurrency などと組み合わせて使いたい / SwiftUI などプロパティラッパーが多用されている場面で注意
DeprecateApplicationMain (SwiftPM 5.10+) SE-0383 Swift 6 @UIApplicationMain@NSApplicationMain@main に置換するだけ
IsolatedDefaultValues (SwiftPM 5.10+) SE-0411 Swift 6 やや易〜普通 -strict-concurrency などと組み合わせて使いたい / 現状に問題があるので積極的に使いたい
GlobalConcurrency (SwiftPM 5.10+) SE-0412 Swift 6 やや易〜普通 -strict-concurrency などと組み合わせて使いたい

基本的に、これからまっさらなプロジェクトを作っていくという場合にはすべて機能を有効にするべきと考えています。これにより Swift 6 が到来した場合にスムーズに移行できるためです。しかし、これらを用いている開発中に何か不明な点が出てきた際、ググって出てくる情報はそれらの機能がオフである前提の話でしょうから、自力で解決する必要があると思います。

一方で、既存のプロジェクトで機能を有効にしていく際には注意が必要です。このフラグによって導入が Swift 6 以降へと先送りにされている機能たちは「破壊的変更を伴うもの(機能有効後にビルドするとエラーになる)」「ビルドエラーにならないが解釈変更により挙動が変わる可能性があるもの」であることがほとんどであり、ソースコードの見直しなどが必要となるからです。

ちなみに - Swift 6 での「Swift 5 モード」

なお、Swift 6 では「Swift 5 モード」を使うことができるため、直ちに大混乱へとなることはないと考えられます。

しかし、せっかくバージョンを上げるのですから、いつまでも「Swift 5 モード」に頼ることなく Swift 6 の世界で生きていきたいですね。

関連

脚注
  1. 原文は "Piecemeal adoption of upcoming language improvements"。日本語訳は stzn/SwiftPodcast をもとにした。 ↩︎

  2. 例えば、Swift 5.10 で使える Upcoming Feature たちは https://github.com/apple/swift/blob/release/5.10/include/swift/Basic/Features.def#L115-L124 で列挙されている。 ↩︎

Discussion