SwiftのRangeはHalf-Open(..<)の方を常用した方が良いかなと思った話
Swift 3.0で、Rangeの型が2つに分かれました。
- Half-Open(..<)
- Closed(…)
以下の記事に書いたとおり、両対応するには通常オーバーロードで2つメソッド用意する必要があって、少し面倒です。
ただ、ライブラリなどはともかく、通常のメソッド定義は、Half-Open(..<)の方だけ用意すれば良いかなと思ってきました。
Half-Open(..<)/Closed(…)が分かれている理由にも書いた通り、元々Closed(…)は構文の違いだけで内部的にはHalf-Open(..<)扱いされていた経緯がありましたし。また、以下の要件など無ければHalf-Open(..<)だけでこと足りますし。
Closed(…)のみ、その要素型のmax値を含めた書き方が出来る(0…Int.maxなど)
NSRangeからRangeに変換するメソッドも、Half-Open(..<)用のものだけしか用意されていないことにも気付きました。
Half-Open(..<)の方が分かりやすく感じる
廃止されたCスタイルのforループは、通常以下のように、<=10ではなく<10でループカウントを指定していたのと同様、
for var i = 0; i < 10; i++ {
print("i: \(i)")
}
Rangeを使ったベターな書き方でも..<10の方が分かりやすいです。
for i in 0..<10 {
print("i: \(i)")
}
以下はあまり直感的に思えません。(文脈にもよりますが)
for i in 0...9 {
print("i: \(i)")
}
単純な引き算のみで要素数をカウント出来る
僕は、5..<10は10–5で5要素、5…9は9–5+1で5要素、といった感じでカウントしていますが、前者の方が直感的で好みです。
Pythonなどのスライスもそうなってる
例えば、PythonではRangeぽいものを1:3という風に表現しますが、これもHalf-Open(..<)です。
a = "12345"
a[1:3]
# → '23'
これ見ても慣習的に、Half-Open(..<)の方が分かりやすいかなと思いました。
本当にClosed(…)が必要な箇所でのみ使うようにした方が意図が明確になりそう
Closed(…)のみ、その要素型のmax値を含めた書き方が出来る(0…Int.maxなど)
こういったケースでのみClosed(…)を使って、それ以外の大半のケースではHalf-Open(..<)を使った方が分かりやすいと思いました。
結果、わざわざHalf-Open(..<)・Closed(…)用の2つのオーバロードを用意せずにHalf-Open(..<)だけで大抵は充分かな、と思った話でした。