ここぽんのーと

コードとデザインの境界に生きるエンジニアの、雑多な記録帳。

[Swift] Optional同士の比較演算の謎

2015/03/21, cocopon

事の発端は、@noliliさんのつぶやき。

Optional同士の比較演算はなぜできるのか?

自分も興味を持ったので、さっそく検証用に新しいPlaygroundを作成。Bool?型の変数を2つ用意して、等価演算と大小の比較演算をそれぞれ試してみます。

2015-03-20 22.42.16

nilの可能性のある値同士で、等価演算(==, !=)はできるけど、大小の比較(<, >など)はエラーになる。直感的です。

ここまで確認して、noliliさんに返信します。

しかし…

話はそう単純ではありませんでした。Int?型だと大小の比較もできるというのです。

そ、そんなはずは…。だって、nilと数値を比較して、どっちが大きいとか小さいとかないでしょう?実際に試してみると…。

2015-03-21 00.07.53

本当だ。マジだ。しかもちゃんと判定結果がBoolで返ってきています。

Optional同士の大小比較

さらに色々試してみます。

2015-03-21 00.37.25

nilInt.minより小さいそうですよ。そう言われましても…。

そもそも、nilになりうる値同士の比較演算って本当に意図した仕様なのでしょうか?途中から参戦した@nakiwoさんが、Swiftの深底を探っていきます。

自分も後を追いかけ、この定義に辿りつきます。

2015-03-21 00.18.15

大小比較可能な(=_Comparable)Optional同士の<比較演算はBoolを返すと書かれています。Int_Comparableを実装しているので、きちんと定義されていることはわかりました。しかしいったい誰得なんでしょう。Optional同士の大小比較、あるとうれしいシーンが存在するのだろうか…?

公式の資料が見つからない

先の検証からも推測できますが、比較演算においてどうやらnilは最も小さい値(Int.minよりも!)をとるようです。このあたりの仕様について公式資料を探してみるも見つからず。

型おじさん@orga_chemにも相談してみたところ、やはり裏付けは取れないものの、同様の考察がされているStack Overflowを見つけてくれました。

(本題から外れるため上ではさらっと流してしまいましたが、整数リテラルがInt?に暗黙的に変換されているあたりも言及されています)

定義されていることはわかったが、疑問は解消されず

今回の調査で、Optional同士の比較演算がちゃんと定義されていることはわかりました。しかし、その演算結果の仕様についての公式な情報には辿りつけませんでした。疑問を整理すると、

  • 大小比較において、nilはどのように判定されると定義されているのか?
  • なぜOptional同士の大小の比較演算が定義されているのか?ハッピーなケースはあるのか?

どうなんでしょう、教えてエライ人。