複数パターンcatch句
Multi-Pattern Catch Clauses
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
Swift の do-catch 文では、従来ひとつの catch 節に書けるパターンはひとつだけで、where 節も 1 組しか付けられませんでした。これは switch 文の case が「カンマ区切りで複数のパターンをまとめ、共通の本体を実行する」書き方をサポートしているのと対照的で、パターンマッチングの仕様に一貫性がありませんでした。
この制約のもとでは、複数のエラーケースに対して同じ処理を行いたいときに、次のような書き方ができません。
do {
try performTask()
} catch TaskError.someRecoverableError { // OK
recover()
} catch TaskError.someFailure(let msg),
TaskError.anotherFailure(let msg) { // 現状は不可
showMessage(msg)
}
そのため実際には、次のどちらかで回避する必要がありました。
catch節を複数に分け、本体の処理を重複して書く。catch節の中でswitchをネストさせ、そこでパターンをまとめる。
do {
try performTask()
} catch let error as TaskError {
switch error {
case TaskError.someRecoverableError:
recover()
case TaskError.someFailure(let msg),
TaskError.anotherFailure(let msg):
showMessage(msg)
}
}
前者は本体の重複を生み、後者は catch 節のパターンマッチング機能をわざわざ無効化して内側で switch をやり直す形になるため、catch でパターンマッチングをサポートしている意義を損なってしまいます。複数のエラーケースを同じ本体で処理したい、という素直なニーズに対して、コードが冗長になりがちだったのが問題でした。
02 どのように解決されるのか
catch 節の文法を拡張し、switch の case と同じように、ひとつの catch にカンマ区切りで複数のパターン(それぞれに任意の where 節を付けられる)を並べられるようにします。実行時に投げられたエラーが、そのうちいずれかのパターンにマッチし、かつ先行する catch 節にマッチしていなければ、その catch の本体が実行されます。
これにより、冒頭の例をそのまま書けるようになります。
do {
try performTask()
} catch TaskError.someRecoverableError {
recover()
} catch TaskError.someFailure(let msg),
TaskError.anotherFailure(let msg) { // こう書ける
showMessage(msg)
}
performTask が TaskError.someFailure("message") または TaskError.anotherFailure("message") を投げた場合、2 つ目の catch の本体が実行され、showMessage(msg) が呼ばれます。
値の束縛
switch の case と同様に、複数パターンを持つ catch 節でも値の束縛を行えます。ただしその場合、switch と同じく、同じ名前の束縛を同じ型ですべてのパターンに含める必要があります。上の例の msg がまさにそのパターンで、両方のパターンで同名・同型で束縛されているため、本体でそのまま利用できます。
文法
拡張後の catch 節の文法は次のようになります。
catch-clauses -> catch-clause catch-clauses?
catch-clause -> 'catch' catch-item-list? code-block
catch-item-list -> catch-item |
catch-item ',' catch-item-list
catch-item -> pattern where-clause? |
where-clause
trailing closure との関係
パース上の曖昧さを避けるため、catch 節のアイテムの中では、末尾に trailing closure を持つ式は書けません。これは switch の case とは異なる挙動ですが、実用上は、必要なら明示的にカッコで囲んで書けば対応できます。
03 今後の見通し
Proposal には、今回のスコープ外として将来の検討対象がいくつか挙げられています。いずれも方向性として示されているもので、実現を約束するものではありません。
すべての catch 節での暗黙のエラー束縛
現在は、パターンを持たない catch 節でのみ暗黙の error: Error が利用できます。これをすべての catch 節に広げられれば、エラーの再スローなどが書きやすくなります。ただし、error という名前をそのまま使うとソース互換性への影響が大きいため、$error のようなコンパイラ定義の識別子を使う案が示されています。
catch 節での fallthrough サポート
switch の case とさらに仕様を揃える方向として、catch 節でも fallthrough を使えるようにする案が考えられます。一方で、外側の switch への fallthrough と衝突してソース互換性を壊してしまうこと、他言語での前例がないこと、具体的な利用シーンが確認されていないことから、現時点では導入しない方針です。
catch 節を条件付きコンパイルブロックで囲む
switch の case に対する既存サポートと揃える方向として、catch 節を条件付きコンパイルブロックで囲めるようにする案も検討されました。本Proposalではスコープを絞るためにいったん見送られ、条件付きコンパイル全体の再設計と合わせて別途検討される想定です。