someとany

# 自分の理解
- some: 関数やComputed Propertiesの返り値で使用。処理の中で１種類のTypeを返したい & 呼び出し元ではそのTypeのProtocolで返り値を扱いたい時に使う。 
- any: existentialである定義をわかりやすくするための書き方

someは多分packageの境界とかで使用するかもなあ。
anyもswift6から必須になるらしいので、今のうちにつけといた方が良いのかも。

# なぜsome、anyがあるのか

## existentialとは
existentialであるとは、参考のサイトを見る限りでは定義にProtocolが使用されているものを指すらしい。

``` swift
protocol Product {
    var id: Int { get }
    var name: String { get }
    var price: Int { get }

    func compareString(product: Self) -> String
}

let product: Product // <- existential
```

## genericsとexistentialの違い
簡単にいうと抽象化した型の推測が効くか聞かないか。

以下の例を見てみる。（あまり良い例ではない気がするので、もし他に良き例が思い付いたらそれにしたい。。。）

``` swift
protocol Product {
    var id: Int { get }
    var name: String { get }
    var price: Int { get }
    
    init(id: Int, name: String, price: Int)
}

struct SmartPhone: Product {
    private(set) var id: Int
    private(set) var name: String
    private(set) var price: Int
    private(set) var isIPhone: Bool = false
    
    init(id: Int, name: String, price: Int) {
        self.id = id
        self.name = name
        self.price = price
    }
    
    mutating func setIsIPhone(_ value: Bool) {
        isIPhone = value
    }
}

func existentialProduct(product: Product) -> Product {
    return product
}

func updateProductPrice<P: Product>(product: P, price: Int) -> P {
    P.init(id: product.id, name: product.name, price: product.price)
}

let phone = SmartPhone(id: 1, name: "iphone se", price: 50000)

let existentialPhone = existentialProduct(product: phone)
existentialPhone.setIsIPhone(true)

var updatedProduct = updateProductPrice(product: phone, price: 100000)
updatedProduct.setIsIPhone(true)

```

productというprotocolと、それを継承したSmartPhoneというstructがある。
SmartPhoneのinstanceを作成し、それを

- existentialProduct(product: Product) -> Product ……(1)
- updateProductPrice<P: Product>(product: P, price: Int) -> P ……(2)

という命令にかけて見ている。この時、(1)の引数、返り値はexistentialである。

この際、(1)の方は返り値がそのままProductとして返ってくるが、
(2)を使用した場合にはPの型が引数の```product: P```から推測されて、SmartPhoneとわかり、返り値の方もSmartPhoneで帰ってくる。

実際、
- existentialPhone.setIsIPhone(true)

はエラーとなる。

## existensialの型のプロパティにアクセス

``` swift
func existentialProduct(product: Product) -> Product
```
の内部でproductのプロパティにアクセスしようとすると、extentialであり、型の推測ができず、実際の値はわからない。
なので、ランタイム時にProduct protocoのデータが格納されているメモリから、実際のSmartPhoneのデータが格納されているメモリへの間接アクセスをする必要があり、少しパフォーマンスが悪い。

対して、

``` swift
updateProductPrice(product: P, price: Int) -> P
```

はコンパイル時に型が推測されるため、ランタイム時には実データへ直接アクセスするので、こちらの方がパフォーマンスが良い。

なので、必要がなければ、なるべくprotocolよりgenericsを使用した方が良い、ということになる。

# any
こちらは簡単で、単に、existentialな定義をわかりやすくするための表現。
なので、（１）は

``` swift
func existentialProduct(product: any Product) -> any Product {
    return product
}
```

のように書ける。

# some
以下の例を通して見ていく。

``` swift
protocol Product {
    var id: Int { get }
    var name: String { get }
    var price: Int { get }

    func compareString(product: Self) -> String
}

struct SmartPhone: Product {
    private(set) var id: Int
    private(set) var name: String
    private(set) var price: Int

    func compareString(product: SmartPhone) -> String {
        let nameCompare = "\(product.name) vs \(name)"
        let priceCompare = "price: \(product.price) --- \(price)"

        return "\(nameCompare) \n \(priceCompare)"
    }
}

func createSmartPhone(id: Int, name: String, price: Int) -> SmartPhone {
    SmartPhone(id: id, name: name, price: price)
}

```

以上の例ではSmartPhoneのinstanceを返すような関数を作成した。
仮定として、この関数がパッケージに入っていて、その外部からこの関数を利用したい、とする。
この時、SmartPhoneでは具体的なクラスがわかってしまうので、なるべくならば隠蔽したい。

パッと思いつくのは以下のような返り値をProductにしてしまうことだが、エラーが出てしまう。
``` swift
func createSmartPhone(id: Int, name: String, price: Int) -> Product {
    SmartPhone(id: id, name: name, price: price)
}
```
なぜか。
Product protocolの関数中で、```Self```を引数として使用しているから。
同様にProtocolが```associatedType```を使用していたりすると、ここで使用することができない。
また、この様に返せたとして、返り値がexistentialであり、少しパフォーマンスが落ちる。

この様な時にsomeを使用する。

``` swift
func createSmartPhone(id: Int, name: String, price: Int) -> some Product {
    SmartPhone(id: id, name: name, price: price)
}
```

この時、呼び出し側では「Productに準拠した何かしらの具体的なクラス」として扱われ、具体クラスを返り値とした時と変わらないパフォーマンスが出せる。また、Selfの問題も無視できる。

ただ、縛りがあり、

- someを返り値とする関数やComputed Propertyの返り値は一意でならなければならない。

という違いがあることに注意する。

なので、この関数の中でProductに準拠したSmartPhone以外のクラスのinstanceを返すことはできない。

このように、someは「一つしか返すクラスの種類はないが、クラス情報を隠蔽したい」ときに使用する。


### （推測）なぜsomeで複数個のクラスが返せないか

**あくまで推測です。記事あったら教えてください。。。**

比較をする際に矛盾が生じるからではないかと推測している。

複数個具体的なクラスを返せる、と仮定してみる。
```some Product```は何かしらの具体的であり、Productを継承したクラスを返したいが、関数自体は具体的なクラスを１つしか指定して返すことができない。

そこで、複数個のクラスを返す代わりに、Productを継承した```SomeProduct```クラスをコンパイルしているときに作成し、代わりに返す様なことが必要になる。

```swift
let flag = true
func _createProduct(id: Int, name: String, price: Int) -> some Product {
    if flag {
        return SmartPhone(id: id, name: name, price: price)
    } else {
        return Instrument(id: id, name: name, price: price)
    }
}
```

といったものがあった際、コンパイルすると、

```swift
let flag = true
func _createProduct(id: Int, name: String, price: Int) -> SomeProduct {
    SomeProduct(id: id, name: name, price: price)
}
```

といった様に解釈される必要がある。
この時、以下の様な時にコンパイル前と矛盾が起きる。

```swift
let flag = true
func _createProduct(id: Int, name: String, price: Int) -> SomeProduct {
    SomeProduct(id: id, name: name, price: price)
/*コンパイル前
    if flag {
        return SmartPhone(id: id, name: name, price: price)
    } else {
        return Instrument(id: id, name: name, price: price)
    }
*/
}

// SmartPhoneクラスのつもり
let a = _createProduct(id: 1, name: "iPhone", price: 100000)

let flag = false
// Instrumentクラスのつもり
let b = _createProduct(id: 1, name: "iPhone", price: 100000)

// ただ、コンパイルされると、a,bのどちらもSomeProductクラスと見做されて、
// ここがTrueになってしまい、矛盾
type(of: a) == type(of: b)
```