[Swift] UnboundedRangeを“呼ぶ”

# 最初に

　この記事は、Swiftのコードを書く上で、実際に役に立つ内容は**書いてありません**。
　ただ、`UnboundedRange`がどのように実装されているのかを考察することで、多少コーディングの幅が広がることはあるかもしれません。
　そして「`UnboundedRange`を“呼ぶ”」とはどういうことなのか、ということは最後まで読んでいただければわかるかと思います…。

# そもそも`UnboundedRange`とは

　`UnboundedRange`は、その名の通りboundの無いrangeのことで、簡単に言えば全範囲を表すものです。コード上では単に`...`と書きます。
　たとえば、`let array: Array<Int> = [0, 1, 2, 3, 4]`という配列があったとき、`array[...]`と書くと、`[0, 1, 2, 3, 4]`という`ArraySlice<Int>`が生成されます。

# `UnboundedRange`はどのように実装されているのか

　幸いにもSwiftはオープンソースなのでその実装を覗き見ることができます。Swift 4.1.2現在、`UnboundedRange`の実装は次のようになっています([ソース](https://github.com/apple/swift/blob/swift-4.1.2-RELEASE/stdlib/public/core/Range.swift.gyb#L1258-L1259)):

```swift
public typealias UnboundedRange = (UnboundedRange_)->()
```

…おや？
`UnboundedRange`は、「`UnboundedRange_`型のオブジェクト(インスタンス)を引数にとって戻り値のない関数」の別名となっているだけでした。

# `UnboundedRange_`とは？

これもソースコードを覗き見てみましょう([ソース](https://github.com/apple/swift/blob/swift-4.1.2-RELEASE/stdlib/public/core/Range.swift.gyb#L1244-L1256))。実装部分だけを抜き出すと次の通りになります：

```swift
public enum UnboundedRange_ {
  public static postfix func ... (_: UnboundedRange_) -> () {
    fatalError("uncallable")
  }
}
```

`UnboundedRange_`は、一つだけstatic関数を持つ空の`enum`でした。

# なぜ`UnboundedRange_`を用意する必要があるのか？

　Swiftの言語仕様上(文法規則上)、`...`はoperator(演算子)であってidentifier(識別子)にはなり得ません。すなわち、`let ...: UnboundedRange = UnboundedRange()`みたいな書き方は絶対にできません。でも、他のrangeと同様に`array[...]`という書き方はしたいという想いを実現したいとします。となると、`...`というoperatorをそのままsubscriptの引数に渡すしかありません。

## operatorを引数にすることはできる

　一方で、Swiftではoperatorを引数にすることはできます。[`Array`の`sorted(by:)`](https://developer.apple.com/documentation/swift/array/2296815-sorted)なんかは有名なところでしょう：

```swift
array.sorted(by:>) // -> [4, 3, 2, 1, 0]
```

なので、`array[...]`という書き方を実現したければ、`...`という適当な関数をでっちあげればいいことになります。

## 適当な関数を用意するために

`...`という関数が、そこらへんにありそうな関数(たとえば`(Int) -> Int`とか)だと混乱を来す可能性があります。(たぶん)そのために、`UnboundedRange_`は生まれたのです。実際のソースコードでは`UnboundedRange_`のstatic関数として`...`が宣言されていますが、グローバルな領域で`public postfix func ...(_:UnboundedRange_) {}`と記述しても大丈夫なはずです。

## これで実現

あとは`Array`側で`subscript(_:UnboundedRange)`(即ち`subscript(_:(UnboundedRange_) -> ())`)を実装すれば`array[...]`と書けるようになります。

### ということは

subscriptの引数に`(UnboundedRange_) -> ()`を渡せば同じ効果が得られるので、次のようなこともできます。

```swift
func f(_:UnboundedRange_) {}
print(array[...] == array[f]) // -> true
```

したからといって何かあるわけではありませんが。


# そして、`UnboundedRange`を“呼ぶ”

これでやっとタイトルの内容に入ることになります。`UnboundedRange`は関数ということが判明しました。関数であるからには、一度は呼んでみたい。そう思うのが人の子ではないでしょうか。
`UnboundedRange`は`(UnboundedRange_)->()`であるので、まずは引数として渡す`UnboundedRange_`のインスタンスを生成することにしましょう。

## `UnboundedRange_`のインスタンスを作る？

`UnboundedRange_`は上記の通り、空の`enum`でした。空の`enum`というのは、そもそも無駄なインスタンスを作らせないために用意するものです。即ち`let u = UnboundedRange_()`とはできないのです。


## `UnboundedRange_`のインスタンスだと偽る

素直にインスタンスを用意することができないことが分かりました。となると、unsafe系の関数を思いつくかと思います。即ち、C言語でいうキャストを(無理やり)行うのです。

たとえば、

```swift
let u = unsafeBitCast(0, to:UnboundedRange_.self)
```

は、どうでしょう？
…結論から言うと残念ながらできません。`Fatal error: Can't unsafeBitCast between types of different sizes`というエラーを吐き出します。`MemoryLayout<UnboundedRange_>.size`は`0`なので`Int`のサイズとは異なるのです。
なので、しかたなく、こうします：

```swift
struct S {}
let u = unsafeBitCast(S(), to:UnboundedRange_.self) // No error
```

これならうまくいきました。
**あとは`u...`とすれば…**

```swift
u... // -> "Fatal error: uncallable"
```

見事、`Fatal error: uncallable`というエラーを吐いてクラッシュしました！
"uncallable"な関数をcallすることに成功したのです。

### 別解

構造体を用意したくないのならば次のようにもできます：

```swift
var i = 0
withUnsafePointer(to:&i) {
  $0.withMemoryRebound(to:UnboundedRange_.self, capacity:1) {
    let u = $0.pointee
    u... // -> "Fatal error: uncallable"
  }
}
```

# まとめ

1. 特定の演算子を引数にする実装を実現したければ、空の`enum`を用意して行うのが吉。
2. unsafe系の関数を使えば、(`public`である限り)呼べない関数はない。