genericsとassociated typeとduck typing(とSwift)
いつもこの辺の話を忘れちゃうのでメモ。
Why does Go not have generic types?
Goに総称型がないっていうネタと議論を永遠に続けるために導入してないんじゃ
理由はFrequently Asked Questions (FAQ) - The Go Programming Languageにある通りだが、厄介なのはissueで延々と議論を続けているところである。やっぱり議論がしたいだけなのでは。
もう少しまとまった説明がproposal/15292-generics.md at master · golang/proposal · GitHubにあるのでこっちを読んだ方が幸せ。そこでは
Generics affect the whole standard library. It is desirable to have the standard library make effective use of generics. Every existing package should be reconsidered to see whether it would benefit from using generics.
などいろいろなことが述べられている。
Swiftの標準ライブラリが1番associated typeの恩恵を受けている気がする。ていうかもはや奴がgeneric protocolを使う姿を想像できない。
「golang と Generics と私」
まあこれ自体は置いといて、Swiftには数値関係のprotocolがたくさんある。なんなら Numeric
という例で出てきたものと同じ名のprotocolまであるがどうか。
Swift標準ライブラリにはprotocolで構成される巨大な継承ツリーがある。その中から数値型を抜粋するとだいたいこうなる:
Swiftの数値型の元締めが問題の Numeric
である*1。 Numeric
は二項演算能力(ただし和差積のみ)を指す。名前が一致しているしこいつが全部解決しそうしない。
なぜなら Numeric
は Self
同士の、つまり同型同士の二項演算能力を指すからである。 Int
/ UInt
/ Float
/ Double
のごった煮の和は管轄外。
演算子システムもしっかり型を限定してくれる Self
先生も好きです(ほんと)
全 Int
/ UInt
/ Float
/ Double
で MyNumber
を実装するのがだるいなら Numeric
1人に実装すれば解決するしない。宣言済みのprotocolに後から別のprotocolを継承することはできない。mattn氏の例と同様に全ての数値型で実装する必要がある。頑張りましょう。
Java の Generics にもの思い - QiitaのJavaでは <T extends Number>
を利用しているが、Javaの数値参照型の元締め Number
は
抽象クラスNumberは、プリミティブ型byte、double、float、int、long、およびshortに変換可能な数値を表すプラットフォーム・クラスのスーパークラスです。
で我らが Numeric
とは別物である。よってこのJavaの例をそのままSwift語に書き換えてもうまくいかない。
Swift: Why Associated Types?
Russ Bishop氏はAppleの中の人らしい。
記事は2015年のもの。現在の Collection
が持つassociatedtypeは
associatedtype IndexDistance = Int
associatedtype Iterator = IndexingIterator<Self>
associatedtype SubSequence
associatedtype Indices
である。いずれにしてもこれを総称型パラメータでやったらヤバイよねっていう話。 https://github.com/apple/swift/blob/781f6326bd9932356086874baa12c812d100565e/stdlib/public/core/Collection.swift
Scalaはtraitでもgenericsとabstract typeを両方使えるので、この記事はOdersky大先生のScalaインタビューを引用している。こちらでもパラメータ数の爆発の可能性が欠点として挙げられている。
The Purpose of Scala's Type System
You could parameterize class Animal with the kind of food it eats. But in practice, when you do that with many different things, it leads to an explosion of parameters, and usually, what’s more, in bounds of parameters.
Introducing Abstract Base Classes
29.7. abc — 抽象基底クラス — Python 3.6.1 ドキュメント
Pythonは基本的にはduck typingなのだがAbstract Base Classesなるものが存在している。記事の最後ではABCとduck typing、generic function、interfaceとの比較がされている。
Python 3.4.0 の新機能 (3) - Single-dispatch generic functions - Qiita
JavaとScalaとC#のジェネリクス機能比較表
よっしゃ!Swiftも参戦だ!
ジェネリックなクラス
class MyList<T> {}
ジェネリックなメソッド
func id<T>(arg: T) -> T { return arg }
型パラメータの上限
func max<T: Comparable>(a: T, b: T) -> T { return a < b ? b : a }
型パラメータの下限
なくない?
型パラメータの推論
id(arg: "foo") // "foo"
全ての型のサブタイプ(ScalaにおけるNothing)
こいつもなくない?
scala.Nothingは何のためにあるのか - kmizuの日記
definition-site variance
記憶にない
use-site variance
記憶にございません
実行時における型パラメータの扱い
(実行時のことは知らん)
型パラメータをnewする
え、無理でしょ( error: non-nominal type 'T' does not support explicit initialization
)
Nominal and Structural Type Systems - soutaroブログ
Swiftに息づくstructural types(構造的型) - Qiita
同じジェネリッククラスを複数同時に継承する
多重継承はダメだし総称型protocolなんて概念はこの世には存在しない
同じ名前で型パラメータの個数が異なるジェネリッククラスを複数作成する
同じ型と認識されるので無理( error: invalid redeclaration of 'Tuple'
)
高階のジェネリクス(Type Constructor Polymorphism)
何これ。
「filterを実装しておけばrejectが勝手に出来上がってる」みたいなやり方はよくあるが。
ジェネリックな型エイリアス
typealias StringDictionary<T> = Dictionary<String, T> let d: StringDictionary<Int> = ["x": 50, "y": 100]
まとめ
みんな違ってみんないい
*1:Strideableも全員に該当する性質だが、こいつはUnsafePointer軍団も監督しているので数値限定ではない。NSNumberもFoundationの子なので違う。