Swift Digest
Blog | Swift.org Blog

Swift 5.9 リリース

Swift 5.9 Released

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

主な変更点

言語と標準ライブラリ

マクロ

マクロは、繰り返しの多いボイラープレートを減らし、表現力の高いライブラリを Swift パッケージとして配布できるようにする仕組みです。マクロには 2 つの呼び出し形式があります。

関数のように単独で展開する freestanding な #マクロ名 形式です。

let _: Font = #fontLiteral(name: "SF Mono", size: 14, weight: .regular)

宣言に付加する @マクロ名 属性形式です。

// stored property の格納をディクショナリへ移し、
// stored property を computed property に変換する
@DictionaryStorage
struct Point {
  var x: Int = 1
  var y: Int = 2
}

マクロは組み込みの言語機能のように働きますが、通常のコードと見分けがつくようになっています。実装は、SwiftSyntax ライブラリを使ってソースファイルに挿入するコードを生成する、ただの Swift 関数として書きます。

マクロにより、ライブラリの利用者は、使われる文脈に応じて適応する強力な機能を簡単に取り込めます。たとえば新しい Observation モジュール(SE-0395)は、Swift のクラスのプロパティが変化したときに他のコードへ自動で通知する仕組みをマクロで提供します。

マクロは macOS と Linux で利用でき、Windows サポートは近日対応予定です。

パラメータパック

パラメータパック(SE-0393)を使うと、任意個数の型に対して動作するジェネリックな型や関数を書けます。

たとえばパラメータパックがないと、任意個の Optional の値がすべて nil でないかを確認する all 関数を書くには、対応したい引数の個数ごとに別々のオーバーロードを並べる必要があり、人為的な上限が生じてしまいます。

func all<W1>(_ optional: W1?) -> W1?
func all<W1, W2>(_ optional1: W1?, optional2: W2?) -> (W1, W2)?
func all<W1, W2, W3>(_ optional1: W1?, optional2: W2?, optional3: W3?) -> (W1, W2, W3)?

パラメータパックを使えば、上限のない 1 つの関数として表現でき、任意個の引数を渡せます。

func all<each Wrapped>(_ optional: repeat (each Wrapped)?) -> (repeat each Wrapped)?

パラメータパックを使う API の呼び出し側は直感的で、追加の作業は必要ありません。

if let (int, double, string, bool) = all(optionalInt, optionalDouble, optionalString, optionalBool) {
  print(int, double, string, bool)
}
else {
  print("got a nil")
}

所有権(ownership)

所有権機能は、性能が重要なコードでメモリ管理の挙動を細かく調整するのに役立ちます。

これらは、今後のさらなる進化の基盤となる大きな機能です。Swift は、より充実した variadic generics と所有権機能を備えた将来に向けて開発を進めています。

その他の機能

Swift 5.9 には、暮らしを快適にする小さな改善も含まれます。

ifswitch を式として使い、変数への代入や戻り値に利用できます(SE-0380)。

statusBar.text = if !hasConnection { "Disconnected" }
                 else if let error = lastError { error.localizedDescription }
                 else { "Ready" }

新しい package アクセスレベル(SE-0386)により、同じパッケージ内の他のモジュールからは API にアクセスできるが、パッケージ外のコードからは隠す、という公開範囲を指定できます。大きなモジュールを複数の小さなモジュールに分割しつつ、内部実装をパッケージの利用者に晒さずに済みます。

並行処理では、結果を生成しないタスクグループ向けの DiscardingTaskGroupSE-0381)と、アクターが実行される環境を正確に制御する custom actor executor(SE-0392)が加わりました。

開発体験

クラッシュ時のバックトレース

Linux では、Swift ランタイムがプログラムのクラッシュや Swift ランタイムエラーを捕捉し、プログラムの出力にバックトレースを表示するようになりました。バックトレーサはプロセス外で動作し、async 関数にも対応します。

この機能は macOS でも利用できますが、デフォルトでは無効です。有効にするには SWIFT_BACKTRACE=enable=yes を設定し、プログラムを com.apple.security.get-task-allow entitlement で署名します。

デバッグ

LLDB と Swift コンパイラに、Swift のデバッグをより速く・確実にする機能が加わりました。

エコシステム

C++ 相互運用

Swift 5.9 では、一定種類の API について C++・Objective-C++ との双方向の相互運用に対応しました。たとえば次のような C++ 関数があるとします。

// Clang module 'PromptResponder'
#pragma once
#include <vector>

std::vector<std::string> generatePromptResponse(std::string prompt);

これを Swift のコードから直接呼び出せます。

import PromptResponder

let codeLines = generatePromptResponse("Write Swift code that prints hello world")
  .map(String.init)
  .filter { !$0.isEmpty }

for line in codeLines {
  print(line)
}

C++ 相互運用は現在も活発に進化しており、実世界での採用から得られるフィードバックをもとに、一部は将来のリリースで変更される可能性があります。有効化の方法や対応する言語サブセットについては、公式の C++ Interoperability ドキュメント を参照してください。

Swift Package Manager

Swift Package Manager にも多くの改善が入りました。

swift-syntax

swift-syntax は Swift コードのパースに不可欠なツールで、新しいマクロ機能を支えています。構文ノード名がより一貫性のあるものになり、新しい SwiftParser のエラー回復が大きく改善され、より正確なエラーメッセージを得られるようになりました。また、構文木の変更された部分だけを再パースする incremental parsing に対応し、ドキュメントも大幅に拡充されました。

サーバ

custom actor executor をはじめとする Swift 5.9 の機能が、サーバ向けエコシステムにも取り込まれつつあります。サーバワークグループは 2023 年の年次アップデート を公開し、主要ライブラリでの並行処理の採用拡大などの計画を示しています。

Windows プラットフォーム

Windows サポートは安定性と開発体験が大きく向上しました。インストーラが Visual Studio のインストール前後どちらでも動作するようになり、複数ツールチェインの並行インストールに向けた初期作業も始まりました。Windows SDK / Visual C++ ツールを制御する新しいフラグの追加、WinSDK モジュールのカバレッジ拡大、C++ 相互運用に向けた vcruntime モジュールの再構成のほか、Structured Concurrency の安定性が大きく向上し、AsyncStream の反復などでのスタックオーバーフローが解消されました。LSP・SwiftPM のパス処理改善や LLDB の初期対応も進んでいます。

Swift 利用者への影響

関連 Proposal・リンク