WWDC22で何が発表されるのか、期待で眠りが浅い日々を過ごしている。何かヒントはないかとSwiftの次期バージョンについて調べていた。
普段から、定期的に同僚のid:ikesyo、id:yutailang0119、id:nakiwo、id:kouki_danらとSwift Evolutionの様子をチェックしていて、おもしろいプロポーザルにはだいたい目を通している(教えてもらっている)のだけど、あらためてみてみると見えてくるものもある。
Swift 5.7になる
現在のSwiftのバージョンは5.6で、次のバージョンはSwift 5.7となる。
Swift 6は破壊的変更のためにとってあるバージョンで、そういう意味ではPython 3のようなフィールもあって不気味だが、期待も高い。
Swiftは(Appleの都合もあってか)半年ごとにマイルストーンを刻んでいる。直近のバージョンで言えば、Swift 5.5でasync/awaitやActorが入って、非同期処理に対する言語的なサポートが充実した。Swift 5.6はそれと較べると小規模な変更で、「チックタック」の「タック」という趣があった。
ではSwift 5.7はどうなるのかというと、広範なアップデートがありそうに見える。
apple/swift-evolution
Swiftの言語に対する変更は、SwiftがOSSであり、Swift Evolutionによる民主的な意思決定プロセスを採用していることから、予め窺い知れることが多い。ということでSwift Evolutionの主なプロポーザルを見ていく。
ここで取り上げるプロポーザルは、すでにSwift 5.7で実装されることが明らかなものもあれば、まだ議論の途中のものもある。また受理されたプロポーザルであっても、実装がSwift 5.7に間に合わないこともある。それでもSwiftの方向性を知るのに参考になるだろうから、混ぜこぜにしている。
構文
SE-0345 if let shorthand for shadowing an existing optional variable
if let
でoptional unwrappingするときにif let a = a {}
をif let a {}
と書けるようにして、冗長さをなくす。
SE-0359 Build-Time Constant Values
コンパイル時に決まる(動的ではない)値の概念を導入する。そのような値は、文字列や数値、真偽値、associated valueのないenum、それらのArray、Dictionary、タプルに限られる。@const
属性を導入し、プロパティや関数の引数に付ける。そのようなプロパティはコンパイル時に決まる値で初期化されていなければならないし、関数の引数もコンパイル時に決まる値でないといけない。これらの制約(コンパイラから見れば保証)を導入することで、コンパイル時にできる処理が増える。
標準ライブラリ
SE-0329 Clock, Instant, and Duration
(Foundationではなく)標準ライブラリに時刻に関する型を加える。非同期処理のようなタスクのスケジューリングに使う。
SE-0358 Primary Associated Types in the Standard Library
「SE-0346 Lightweight same-type requirements for primary associated types」で導入されたprimary associated typesを標準ライブラリでも設定する。
正規表現
SE-0348 buildPartialBlock for result builders
(「SE-0351 Regex builder DSL」を見越して)result buildersにフックとなるメソッドを追加して、挙動をカスタマイズしやすくする。このフックによってオーバーロードを減らせる。
SE-0350 Regex Type and Overview
正規表現型の導入。キャプチャされた値の型を型パラメータで表現するところがSwiftらしい。
SE-0351 Regex builder DSL
Result buildersでDSLを作り、正規表現を組み立てられるようにする。おもしろい。単におもしろいだけでなく、キャプチャした値を何らかの型に変換する処理も組み込める。
SE-0354 Regex Literals
正規表現リテラルを言語に組み込む。リテラルはコンパイル時に評価され、正規表現として妥当であることが保証され、キャプチャの型も決まる。DSLにも組み込める。Swift 6以降は/
のみで使えるが、Swift 5.7の時点では演算子の互換性の都合から#/
を使う。
SE-0355 Regex Syntax and Run-time Construction
実行時に文字列から正規表現を作る。
SE-0357 Regex-powered string processing algorithms
String
やCollection
に正規表現を活用するメソッドを追加。パターンマッチの追加。
非同期処理関連
SE-0302 Sendable and @Sendable closures
Sendableの概念自体はSwift 5.5からあるが、Sendableのチェックに関する警告は有効になっていなかった。Swift 5.6で有効にされそうだったが、あまりにも警告が多くなりすぎることから、結局無効にされた( https://github.com/apple/swift/pull/41368 )。Swift 5.7でついに有効になった。ついでに-warn-concurrency
オプションが-strict-concurrency=(minimal|targeted|complete)
になっている( https://github.com/apple/swift/pull/42523 )。
SE-0338 Clarify the Execution of Non-Actor-Isolated Async Functions
Actorのasync関数から、他のactorに紐付かないasync関数を呼び出すとき、これまではactor上で実行されてしまっていた。これをやめて、actorに紐付かないasync関数は常にグローバルに共有されたプールで実行されることになる。これに伴ってSendableのチェックも行われる。
SE-0340 Unavailable From Async Attribute
Async関数はawait
の前後で実行されるスレッドが同一とは限らない。このような環境で呼び出されることを意図してない(単一のスレッドから呼び出されることを意図している)関数について、async関数からの呼び出しを防ぐように宣言できる。
SE-0343 Concurrency in Top-level Code
トップレベルでawait
できる。このときグローバル変数は暗黙的に@MainActor
が関連付けられる。
分散actor
Actor間のやりとりを拡張していくと、(やりとりするメッセージがシリアライズできるなら)個々のactorが同一のプロセス、あるいは物理マシンに存在しなくてもいいんじゃないか、となっていく。しかしこれらが実際にどういうものになるのか、門外漢すぎてわかっていない。
SE-0336 Distributed Actor Isolation
SE-0344 Distributed Actor Runtime
型システム関連
SE-0309 Unlock existentials for all protocols
Associated typeやSelf
を持つprotocolでもany P
としてexistential typeのように扱える。これまではジェネリクスの制約として使うしかなかった。any
という表現はSwift 5.6の「SE-0335 Introduce existential any
」ですでに実装されている。
SE-0326 Enable multi-statement closure parameter/result type inference
式が2つ以上のクロージャで、引数や返り値の型推論を有効にする。これまでも式が1つなら型推論されていたが、型チェッカーのパフォーマンスの問題で式が2つ以上のときは型を明示する必要があった。実装の改善でパフォーマンスの問題を解消できたため、2つ以上でも型推論を有効にさせられる。
SE-0328 Structural opaque result types
Opaque result typeは、protocolを返り値の型としてsome P
のように書けるもので、Swift 5.1から導入されている。これを拡張して、(some P)?
や(some A, some B)
や() -> some P
のようなパターンも書けるようにする。
SE-0341 Opaque Parameter Declarations
Opaque typeのsome P
を引数の宣言でも使えるようにする。これまでは型パラメータを制約する形で表現していた。
SE-0346 Lightweight same-type requirements for primary associated types
Protocolが1つ以上のassociated typeを持つとき、その一部をprimary associated typeであると宣言できる。Primary associated typeはProtocol<AssociatedType>
というジェネリクスと同様の構文で実際の型を指定できる。これによって表記が簡単になる。
SE-0347 Type inference from default expressions
関数の引数の型にジェネリクスで型パラメータを使っていても、型推論によってデフォルト引数を持てるようにする。
SE-0352 Implicitly Opened Existentials
あるprotocol P
について、any P
をsome P
として渡せるようにする。
SE-0353 Constrained Existential Types
「SE-0346 Lightweight same-type requirements for primary associated types」でprimary associated typesが設定されたprotocolがexistential typeとして使える。
SE-0360 Opaque result types with limited availability
Opaque result typeを使っていて関数の返り値がsome P
のとき、その関数が実際に返す具体的な型T
は常に一致している必要がある。例えば関数の中で条件分岐して、ある場合はA
、ある場合はB
を返したりはできない。これを緩和して、#available()
による条件分岐に限って型が違ってもいい、とする。
Swift Package Manager
SE-0339 Module Aliasing For Disambiguation
利用するモジュールに別名を与えて紛らわしくなくできる。
SE-0356 Swift Snippets
Swift Packageにスニペットを追加できる。
Swift 5.7の傾向
こうしてプロポーザルを概観すると、大まかな傾向が掴めるはずだ。
非同期処理関連の改善がいくつか見られる。データ競合を引き起こさない安全な平行処理のために、そしてSwift 6で完全に近い保護を達成するために準備が進められている。
わかりやすいのは正規表現に関するプロポーザルが多いことで、一連のプロポーザルによって、正規表現はSwiftの一級市民になる。Swiftでは何年も前にString Manifestoというのが議論されていて、このときに(正規表現ではないが)文字列のパターンマッチングが俎上に載せられていた。今回の正規表現について、これの一環とも思える。
もうひとつ、型システムについて大幅な改善がある。Opaque result typeのsome
やexistential typeのany
、あるいはprimary associated typeによって、protocolの使い勝手が(あるいは書き味が)かなりよくなる。これらの一部はGenerics Manifestoで議論されていたが、ついに大きく手が入った格好である。
Swiftの進化による期待
ここで手が入った機能の多くは、例えばSwiftUIに大きな影響を与えそうだ。SwiftUIはSwiftの言語機能を活かしているし、特に型システム周りでは恩恵が大きそうに思う。
勝手な期待では、SwiftUIのナビゲーションをもっと抽象的に、あるいは宣言的に扱いたい。そういう機能が追加されるとして、アプリ内の任意の画面にディープリンクを設定するなら、正規表現の言語的サポートも大いに役立ちそうだ。
加えて、Swiftの言語的な進化による、Swiftのためのライブラリやフレームワークの進歩も期待している。Apple製のフレームワークのうち新しいものには、Swiftからのみ利用できるものが出てきている。それらはSwiftの言語機能を活かしていて、堅牢で使いやすい。今後もそのような、例えばasync/awaitやactorをうまく活用したフレームワークが増えていくだろうことに非常に期待している。例えばデータの永続化について、Swiftyなものが出てきてほしい。
ということで、今年もWWDCを楽しみにしています。