Normalizing naming for “negative” attributes
01 何が問題だったのか
Swift 2 までの言語機能には、属性のうちに no を接頭辞として付けた「否定」の名前を持つものがいくつか存在しました。代表的なのは次の二つです。
@noreturn— 関数がリターンしないこと(例外的な終了やfatalErrorのように制御が戻ってこないこと)を表す属性。@noescape— クロージャのパラメータがその呼び出しのスコープを超えて保持されない(エスケープしない)ことを表す属性。
@noreturn func crash() {
fatalError("unreachable")
}
func apply(@noescape _ body: () -> Void) {
body()
}
これらはいずれも「〜しない」という性質を表す形容詞的な修飾ですが、名前の作り方を見ると、英語として修飾子の性質を表すなら本来は non-returning / non-escaping のように non- を使うのが自然です。no を使った場合、その後に続く動詞や名詞との境目でキャメルケースの凹凸が生まれやすく(noReturn / noEscape のように切らざるを得ない)、一語の形容詞として見たときの一体感を損ねます。
Swift は「属性は、修飾する対象の性質を表す一語の形容詞として組み立てる」という方針を取っており、@noreturn / @noescape だけがこの方針に沿っていない不揃いな状態でした。そのため、名前の付け方をそろえるために、これらの属性を「non- を接頭辞とした一語の形容詞」に置き換えることが検討されました。
02 どのように解決されるのか
この提案は Rejected(却下) となりました。@noescape と @noreturn を @nonescaping / @nonreturning に改名する変更は採用されず、別の方向で整理が進められました。
提案されていた内容(採用されなかったもの)
提案自体はごく小さく、次の2点の改名を行うだけの内容でした。
@noreturnを@nonreturningに改名する。@noescapeを@nonescapingに改名する。
もし採用されていれば、先ほどの例は次のように書くことになっていたはずです。
// 採択されていた場合のイメージ
@nonreturning func crash() {
fatalError("unreachable")
}
func apply(@nonescaping _ body: () -> Void) {
body()
}
既存コードは、属性名を機械的に置き換えるだけで移行できる想定でした。
却下の経緯と、その後の整理
レビューでは、「名前をそろえること自体には意味があるが、改名という形で解決するのが正しいのかは別の問題だ」という議論が中心となりました。特に @noreturn については、”point of no return”(引き返せない地点)のように英語の慣用表現としての “no return” が定着しており、@nonreturning よりも @noreturn のほうがむしろ読み手に意図が伝わりやすい、という指摘もありました。
また、これらの属性のうち、@noreturn と @noescape はそれぞれ別の方向で置き換えが進められることになります。
-
@noreturnは、SE-0102 によって属性そのものが廃止され、戻り値の型をNeverにする方式に置き換えられました。Neverは値を生成できない空の型で、関数が正常に戻ってこないことを戻り値の型として表現できます。// 現在の Swift func crash() -> Never { fatalError("unreachable") } -
@noescapeは、SE-0103 によって扱いが反転しました。すなわち、クロージャのパラメータは既定で non-escaping となり、エスケープする場合にだけ@escapingを明示的に書く、という形に整理されました。否定形の属性を廃し、肯定形の属性だけを残す方針です。// 現在の Swift func apply(_ body: () -> Void) { // 既定で non-escaping body() } func store(_ body: @escaping () -> Void) { // エスケープする場合だけ明示 handler = body }
結果として、「no- 始まりの属性名をどうそろえるか」という問いは、SE-0097 が提案した形(non- への改名)ではなく、そもそも否定形の属性を言語から取り除く方向で解消されました。今日の Swift では @noreturn / @noescape のいずれも存在せず、Never と @escaping の組み合わせで同等以上の表現ができるようになっています。