Lowercase didSet and willSet for more consistent keyword casing
01 何が問題だったのか
Swift には、プロパティの値が変化する前後に任意の処理を挟み込むための プロパティオブザーバ があります。宣言は次のように、willSet と didSet というキーワードを var の宣言ブロックに書く形でした。
struct Counter {
var count: Int = 0 {
willSet {
print("これから \(newValue) になります")
}
didSet {
print("\(oldValue) から変わりました")
}
}
}
ここで使われている willSet / didSet は、Swift のキーワードのなかではやや珍しい キャメルケース の表記になっています。一方で、同じように二語を連結したキーワードでも、Swift では以下のようにすべて小文字で連結するスタイルが採られています。
typealiasassociatedtypefallthrough
Swift は「キーワードは一語の原子的な概念として扱えるよう、連結語であっても小文字でつなぐ」という方針をとっており、willSet / didSet だけがこの方針に従っていない不揃いな状態でした。この提案は、その不揃いを解消するために willSet / didSet の表記を見直すことを目的としていました。
02 どのように解決されるのか
この提案は Rejected(却下) となりました。willSet / didSet は現在の Swift でもキャメルケースのまま維持されており、全小文字の willset / didset に変更されることはありません。
// 現在の Swift でもこの書き方のまま
struct Counter {
var count: Int = 0 {
willSet {
print("これから \(newValue) になります")
}
didSet {
print("\(oldValue) から変わりました")
}
}
}
以下では、提案されていた内容と却下の経緯を整理しておきます。
提案されていた内容(採用されなかったもの)
提案の本体は次の一点だけで、挙動は一切変えずにキーワードの表記だけをそろえる、というものでした。
willSetをwillsetに、didSetをdidsetにそれぞれ改名する。
加えて、今後 Swift に追加されるであろう類似のキーワード(例として didchange が挙げられていました)も、同じ方針で全小文字を採用することが明示されていました。既存コードに対しては、キーワードを機械的に置き換えるマイグレーションだけで移行できる想定でした。
もし採択されていれば、先ほどの例は次のように書くことになっていたはずです。
// 採択されていた場合のイメージ
struct Counter {
var count: Int = 0 {
willset {
print("これから \(newValue) になります")
}
didset {
print("\(oldValue) から変わりました")
}
}
}
なお、当時同じように扱いが議論されていた dynamicType については、この提案の範囲外とされ、別途整理されることとされていました(後に SE-0096 で演算子 type(of:) として置き換えられています)。
却下の経緯
却下の主な理由は、表記をそろえることのメリットよりも、既存コードへの影響や読みやすさの低下といったコストのほうが大きい、と判断された点にあります。willSet / didSet は「何かを set する前 / 後」という二語の結び付きがそのまま読める名前であり、全小文字にしてしまうと willset / didset のように語の切れ目が視覚的に分かりにくくなる、という指摘がありました。
また、Swift のキーワード命名方針は一貫した規則として明文化されているわけではなく、typealias / associatedtype / fallthrough のような既存の全小文字キーワードはいずれも歴史的な経緯で採用されてきたものです。そこにあえて willSet / didSet を合わせるために広範なソース互換性を壊す価値は見出せない、というのが結論でした。
結果として、willSet / didSet は今日の Swift でもキャメルケースのまま使われ続けており、プロパティオブザーバの書き方自体にこの提案は影響を与えていません。