Swift Digest
SE-0109 | Swift Evolution

Remove the Boolean protocol

Proposal
SE-0109
Authors
Anton Zhilin, Chris Lattner
Review Manager
Doug Gregor
Status
Implemented (Swift 3.0)

01 何が問題だったのか

Swift には歴史的経緯から、真偽値を抽象化するための Boolean というプロトコルが標準ライブラリに存在していました。これは具体的な真偽値型の違いを吸収するために用意されたもので、Bool と並んでドキュメントやコード補完の候補に現れていました。

しかしこの Boolean プロトコルには、次のような問題がありました。

  • Bool と見た目が似ているのに意味はまったく異なり、Swift を学び始めた人にとって紛らわしい存在になっていた
  • 真偽値は十分に単純な概念であり、複数の具体実装を抽象化するためのプロトコルを用意する必要性が乏しかった
  • Objective-C の BOOL は、現在ではほとんどの箇所で自動的に Swift の Bool にブリッジされるため、ブリッジのためのプロトコルとしての役割もすでに失われていた
  • 真偽値を受け取る API のほとんどは Bool を直接使っており、Boolean プロトコルはライブラリ全体で一貫して利用されていなかった

結果として、実質的に Boolean を使っていたのは標準ライブラリの単項 ! 演算子と、二項の && / || 演算子だけという状態であり、抽象化としての価値が見合っていませんでした。

02 どのように解決されるのか

この提案では、標準ライブラリから Boolean プロトコルそのものを削除し、!&&|| の三つの演算子を Bool を直接扱うものに変更しました。これによって、真偽値まわりの型は Bool に一本化され、Boolean という別のプロトコルが並び立つことによる混乱が解消されます。

既存コードへの影響

この変更はソース互換性を破る変更ですが、実際のコードが壊れる可能性はほとんどありません。Objective-C の BOOL を受け取る・返す API は自動的に Bool にブリッジされるため、普段のアプリケーションコードから見える挙動は変わりません。

Boolean の影響が見える代表例は、Objective-C コレクションの列挙 API にある STOP 引数のように、ObjCBool が直接顔を出すケースです。

class NSArray: NSObject {
    func enumerateObjects(
        _ block: @noescape (AnyObject, Int, UnsafeMutablePointer<ObjCBool>) -> Void
    )
}

x.enumerateObjects { value, index, STOP in
    STOP.pointee = true
}

このコードでは STOP.pointeetrue を代入していますが、ObjCBool は引き続き BooleanLiteralConvertible に適合しているため、Boolean プロトコルが無くなっても真偽値リテラルからの代入はそのまま動作します。

結果

この変更により、Swift では真偽値を表すプロトコル的な抽象は存在しなくなり、Bool が唯一の真偽値型として扱われるようになりました。!&&||Bool 専用の演算子になり、標準ライブラリの API 設計と実際のコードの使われ方がそろった形となります。