幾つかの気になるブログも見終わりまして、再び本編の
クロージャーにおける循環参照
に戻ろうかと思っていたのですけれど、時を同じくして Swift 5.9 もリリースされました。そんなせっかくの機会なので、新たに導入される機能みたいなところを眺めてみようと思います。とはいえぜんぶは理解できていないため、自分の知っているところを中心に見ていくことになりますけれど、どうぞよろしくお願いしますね。——————————————————————————————————————————
熊谷さんのやさしい Swift 勉強会 #300
00:00 開始
00:12 今回の展望
02:01 Swift 5.9 の新機能
03:17 C++ Interoperability が魅力的
06:06 Swift マクロで出来ること
09:10 マクロは Swift 入門書にも載っている技術
11:26 マクロも普段使いなターゲットのひとつ
14:25 可変長ジェネリクスを使うには慣れが必要そう
16:26 パフォーマンスをコントロールするための、所有権
18:11 所有権が実用的になるのはもう少し先になりそう
18:50 そのほかの Swift 5.9 の新機能
20:41 C++ Interoperability の概要
21:36 Swift Package Manager にも手が加えられているらしい
22:36 Swift 5.9 で取り込まれたプロポーザル
24:08 前方宣言
26:22 めずらしく、タプルを返す標準機能
28:33 複製できない構造体は発展途上
32:48 複製不可な構造体は deinit を持てる
36:22 Observation はアプリ作りで注目されている様子
37:16 Never 型が Codable に準拠したらしい
41:16 クロージングと次回の展望
——————————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #300
始めましょう。今日は、ここ数ヶ月ずっと他の方のブログを見ていましたが、そろそろ本編に戻れそうだと思います。本編について念のため説明しますと、この勉強会はAppleの「The Swift Programming Language」に沿って進めています。最近は脱線しがちでしたが、そろそろ本来の目的に戻ろうと思います。
特に、最近注目すべきはXcode 15の登場とSwift 5.9のリリースです。この勉強会は一般公開するため、Swift 5.9がリリースされるまでは新しいバージョンに触れるのが難しい状況でした。リリース前にあまり深く触れることができなかったので、せっかくですからXcodeで実際に動かしながら新機能に触れ、勉強会の時間を使って慣れていけたら良いと思います。
まず、Swiftの公式ページにはSwift 5.9のドキュメントが公開されています。確か、最新のリリース情報の中にSwift 5.9がありましたね。具体的なドキュメントのURLを見つけられていないのですが、一般的な「The Swift Programming Language」のドキュメントとは異なる場所にあるはずです。
さて、Swift 5.9の新機能で個人的に興味深いのがC++との互換性です。これは、Objective-Cとのインターオペラビリティと同じような形で、SwiftからC++を利用できるというものです。まだ詳細を掴み切れていませんが、Objective-C++も視野に入っているようです。
昔、私はObjective-C++に魅了され、様々なコードをObjective-C++とC++で書いていました。その時に、Objective-C++のコードをSwiftで呼ぶのが非常に苦労しました。具体的には、一度Objective-Cに変換し、そのインターフェースのラッパーを作成し、それをSwiftで使用するという手間がかかりました。これにより、一つのクラスに対して4つぐらいのファイルが必要になっていました。
そうした経験もあって、C++互換性の強化は非常に興味深いです。ただ、ソースコードは10年も経つと使い物にならないことが多いので、まだ試していません。しかし、C++が得意な人や最適化されたコードを書きたい人には有効な機能だと思います。また、C++ライブラリをインポートするなどの使い方も考えられます。
それとは別に、Swift 5.9の新機能として注目すべきなのはマクロ機能です。まだ詳しく追いかけていないのですが、これについても好んで使う人がいるかもしれません。他にも色々な新機能があるので、これから少しずつ見ていきたいと思います。 もちろん、プライベートなプロダクトでも全然オッケーです。ただ、このマクロでできることは、コンパイル時にビルドする前にあらかじめ作っておいたルールに従ってコードを展開することです。ここでの「展開する」というのは、既存のコードに追加することを指します。既存のコードを書き換えたり消したりすることはできません。
マクロとしては「スイートシンタックス」というのを使ってソースコードを解析し、変換していくもののようです。マクロには主に2つのタイプがあります。1つは「装飾する」ためのマクロ、もう1つは「スタンドアロン」で独立して動くマクロです。Swiftの特徴として、これらのマクロはSwiftの言語仕様で定義できます。Swiftは他の言語の書き方を勉強させず、Swiftの書き方で様々なことをできるようにするというコンセプトがあります。
たとえばプロパティアフォードやリタルトビルダーなどのドメイン固有言語もSwiftコードで定義できます。また、SwiftのパッケージマネージャーもSwift言語で定義されており、YAMLなど他の形式を使わずに済むようになっています。同じように、マクロもSwift言語で定義し、適切なプロトコルに準拠させて実装していくという作りになっています。
このマクロに関しては、自分ももう少し勉強して、知識がついてから改めて紹介しようと思います。マクロというと特別なツールのように感じますが、『The Swift Programming Language』にもちゃんと記載されています。このドキュメントの中では、マクロについても詳しく説明されています。その概要を押さえた上でSwiftの文法を勉強し、実際に作っていく必要があります。
マクロの実装については、まずプロトコルに準拠させてコードを書いていきます。また、パッケージマネージャーを使ってマクロをターゲットにし、Xcodeにもマクロのターゲットを設定します。この勉強会では、例えばエクステンションを作成するような感覚でマクロについて学んでいくことになるでしょう。
マクロを自分で実装する機会はあまり多くないかもしれませんが、一度触れて慣れておくと、いざというときに使えるようになると思います。これはプロパティラッパーと同じ感じで、プロジェクト内で使わなくても知識として持っておくことで応用範囲が広がります。突然の登場でも慌てずに対処できるようになります。 とりあえず、向き合っておくといいのかなと個人的には思いますが、わからないことも多いですよね。どのレベル感で話すかによりますが、チームでの勉強会なので、あまり軽く持ち出すものではない気がします。どちらにせよ、この話題についてはおいおい話すとして、まずは調べてから話そうと思います。もちろん、今すぐ話したい人がいれば、話してくれてもオッケーです。自分が調べていなくても全然問題ありません。
次にどこを見ておくべきかというと、パラメータの扱いですね。これも難しいテーマです。いわゆるジェネリクスの型の数、型じゃない引数の数を動的にできるという機能です。このようにパラメータを取って、それを一発で扱うといった感じです。各型に対して各型を並べて取ることができます。
このリピートというキーワードがなかなか厄介で、癖がありますね。使い慣れていかないと難しいです。理屈ではわかっていても、実際に使おうと思うと難しいことが多いです。例えるなら、待機呼び出しが苦手だった経験がある人もいるかもしれませんが、同様の難しさがあります。待機呼び出しも理屈では理解できても、実際には使いこなすのが難しいです。
また、Prologというプログラミング言語があり、論理型の言語なんですが、「AならばB、BならばC、ではAならばC」といった感じの言語です。これも理屈ではわかっていても、自分でコーディングしようとすると難しい。同様に、理解と実際の使用には大きなギャップがあると感じます。これも後で試してみたいですね。
さらに、オーナーシップという概念もあります。今日の機能一覧にどどんと出ていて、なおさら難しそうです。以前は共有資源やコピーイン・コピーアウトといった概念がありましたが、今では消費という考え方が加わりました。プログラマーが一方的に最適化をかけられるようになったという仕様です。以前はコンパイラが判断して最適化してくれていたのですが、限界があるため、プログラマーにも委ねられるようになりました。これによってハイパフォーマンスなコードを書くことができるようになります。
このオーナーシップを指定したからといって、「ここは最適化できるよ」という目安にはなりますが、必ずしもそうなるとは限りません。最適化はあくまでコンパイラの判断による部分もあります。実際に効果的に使えるようになるのは、もう少し時間がかかるかもしれませんが、基本的な動作に慣れれば難しくないと感じるでしょう。
また、パッケージアクセスレベルに関しても、これまでは
public
、internal
、private
、fileprivate
、open
がありましたが、新たにpackage
が追加されました。これはスイフトパッケージマネージャーを使ってターゲットを複数追加できる機能です。まだ実際に使っていないので、具体的な使い方はこれからですね。マクロについても言及していますが、マクロを作成して他のライブラリから内部アクセスできるようにする機能もあるかもしれません。これについても、今後試していくべき部分だと思います。
以上の内容を踏まえて、この勉強会でもっと深掘りしていければと思います。 それでは、今回のテキストを自然な文章に整えていきますね。
さて、いろいろと細かい調整がありますが、C++とのインターオペラビリティについてお話ししましょう。C++のインターフェースについて書かれているのですが、マップや配列のようなものがあります。例えば、特定の関数名や引数名があり、C++の文字列型である
std::string
を使ってプロンプトを表示することができます。このように、SwiftとC++の総合運用が可能であり、逆もまた然りです。このドキュメントに詳細が記載されているので、後でじっくり読んでみようと思います。次に、パッケージマネージャーについてです。先ほど言っていたターゲットについてですが、プロジェクトに新たに追加された機能がいくつかあります。ネットワークコネクションやファイル操作関連のパーミッション管理などが強化されています。この辺についても、後ほどじっくり見てみるつもりです。
それから、UNIXドメインソケットの話もありますね。UNIXのソケットは権限が必要な場合がありますが、それに関連したことではないようです。パッケージマネージャーの機能強化は、私にはあまり詳しく理解できませんが、他にもいろいろとあります。
続いて、Linux周りのデバッグについても紹介がありました。しかし、Linuxの細かなことについてはまたの機会にしましょう。SwiftのEvolutionのプロポーザルに書かれている内容を見たほうが理解が深まりやすいです。
例えば、
Optional
でのmap
やflatMap
のような操作についての提案があります。これがオーナーシップと関連しているようです。他にも、タスクのスリープ機能が強化されるという話もあります。クロック型が搭載され、以前はTask.sleep
で実現していた機能が改善されるようです。if
とswitch
の評価式は便利ですね。これでより簡潔なコードが書けるようになります。また、ディスカーティングタスクグループという新たなコンカレンシー機能も提案されています。さらに、エクスプレッションマクロについても議論されています。この辺りは、マクロによるコード展開の話です。オブジェクティブCとのインターロペラビリティも含め、C言語やC++の独特な書き方に関する提案もあります。インポート時に順序を気にする必要があるという問題についても触れられていました。このような細かな違いに注意を払うことで、総合運用性が向上しますね。
以上が今回のトピックの概要です。また、具体的な内容については次回以降に詳しく見ていきましょう。 Swift言語では、オブジェクティブ-Cクラスをフォワードデクレアできるようになっていますが、実体が伴わないため、実装したコードをインポートしない限りは機能しません。このように実体が伴わない場合、Swift Interoperabilityはエラーを出してくれるので、安全なプログラム設計が可能です。
例えば、
AsyncStream
のmakeStream
が簡単になりました。この機能を使うことで、コンティニュエーションとストリームをタップルで受け取り、ストリームにはループ操作を行いつつ、コンティニュエーションに対して何か処理を行うことができるようになりました。このような機能は、Swift標準ライブラリーで珍しいとされています。AsyncStream
をまだ使っていない人には難しいかもしれませんが、このような方法でまとめると、それぞれのタスクでコンティニュエーションやストリームを制御する際の可能性が広がります。タスクが分かれている場合は共通のデータ構造体を使わずにタップルとしてまとめることもできます。次に、
@attached
マクロの話です。コピー不可な構造体や列挙型に関するもので、これにより誤ってコピーされることを防ぐ設計が加わりました。コピーが禁止されていると、代入文を書いてもコピーが行われないのです。現在のSwiftではまだ一般的でない機能ですが、今後の標準となる可能性があります。このような機能は他のプロトコルに対しても応用できるかもしれませんが、まだ対応していないものが多いです。特定の条件下でオブジェクトに対して安全な操作が可能になるという利点はありますが、現在は特定の制約があります。
例えば、ノンコピアブルな構造体は他のプロトコルに準拠できないという制約があります。これが改善されればさらに幅広い利用が可能になりますが、現状ではまだ試行錯誤の段階といえます。それでも、こうした新機能をうまく活用することで、より効率的かつ安全なコードを書くことができるでしょう。 なので、
String
に対して再準拠できないという点では、非常に厳しい要求が求められることになります。そのため、利用を避けたいと感じることもあるでしょう。しかし、簡単なファイルディスクリプターやファイルハンドルを使い回す場合には便利な機能です。この設定を追加すると、複製しようとするとコンパイルエラーになります。そうすることで、オーナーシップの概念が明確になります。たとえば、あるリソースは「貸し出した」とか「譲る」といった管理ができるようになるのです。これがオーナーシップのイメージです。もちろんオーナーシップの全てではありませんが、概略としてはこういうイメージです。ノンコピアブルな構造体の特徴として、リソースを一つのインスタンスで管理できることが挙げられます。唯一のインスタンスであり、コピーができないため、その1インスタンスがリソースを管理できるようになるのです。この説明だけを聞くとシングルトンのように思いますが、実際は違う話です。
さらに、ノンコピアブルな構造体は
deinit
を値型に持つことができます。deinit
を使いたいだけであれば、クラスで実装することでも問題ありません。しかし、構造体にすることでスタックメモリーに配置され、ヒープメモリーと比べてパフォーマンスが向上するケースが多いです。スタックメモリーにはdeinit
を含めた後始末が含まれ、より効率的に処理が行えるので、スウィフトにおいても重要な機能です。現在、ある制約下ではプロトコルに準拠できない場合もありますが、将来的には役立つ機能になると考えられます。そのため、今のうちに学習して慣れておくと良いでしょう。
コピアブルについては、最近の機能であり、以前は利用できなかった部分もありますが、今後も注意深く見守る必要があります。このようなメモリー管理の機能は特にSwiftからプログラミングを始めた方には馴染みがないかもしれませんが、他の言語でも役立つ知識となります。いろいろと試してみると良いでしょう。
また、カスタム型やバリアティックジェネリクス、パッケージマネージャーのマクロサポート、オブザーブ関連の機能など、新しい機能や更新も注目されています。特にオブザーブの機能は、アプリ開発側の人にとって使いやすくなるよう改善が進められている点も興味深いでしょう。
全体的に、これらの新しい機能や改善はSwiftをより強力で使いやすい言語に進化させる要素となります。今後も引き続き学習を続けていくと良いでしょう。 Swiftの話題ですが、他のプログラミング言語を使っている人も耳にしやすいものですね。そのためにSwiftに導入された機能の話をします。面白いのが、
Never
型がCodable
に準拠したという点です。これが何に使われるのかと思ったのですが、Never
型を使う際にCodable
に準拠できないと困る場合があるため導入されたようです。まだ詳細は確認していないのですが、何か良い点があるのかもしれません。また、
Never
型がデコードされた場合のエラーを考えるとコンパイルエラーが起きるでしょう。詳細は確認しておきます。この辺りはNever
型がCodable
に準拠しましたという話です。次に、ジェネリックマクロについてです。具体的には
Variadic Generics
ですね。これが導入されました。TypeAlias
も利用できるようになったようで、なかなか強力な機能ですが、応用には時間がかかりそうです。さらに、
Initializer Accessors
と呼ばれる機能も追加されました。これはプロパティラッパー周りの問題を解決するためのものです。計算型プロパティへのアクセスが可能になるような内容ですが、まだ十分に理解できていないので、詳細をもう少し確認しなければなりません。これまでの話から、Swift 5.9でいろいろな新機能が搭載されたことがわかります。その中でもハイライトとして、マクロ、ジェネリック、
Variadic Generics
、オーナーシップなどが注目されます。今日はこれらをざっくり紹介しましたが、次回はもっと細かくこれらをいじりながら雰囲気を掴んでいきたいと思います。次回のテーマですが、まずオーナーシップから話すのがよさそうです。その後、
Variadic Generics
、マクロの順で進めることを計画しています。これで3回以上のセッションになるかもしれませんが、細かな部分も見ていくことで理解を深めていければと思います。次回はオーナーシップについて、前回紹介したノンコピーアビリティも含めて、もっと詳しく見ていきます。これで今日は終わりにします。お疲れ様でした。ありがとうございました。


