Upload
yuichi-adachi
View
2.374
Download
2
Embed Size (px)
Citation preview
Swift2.xを Scalaから見る
1
安達 勇一 クラスメソッド株式会社2015年11月11日
Ⓒ Classmethod, Inc.
2
安達 勇一• 2013/12 入社
• TwitterID: @UsrNameu1
• Github: https://github.com/UsrNameu1
• Blog: http://dev.classmethod.jp/author/yad
• ここ半年はサーバーサイドメイン
Topics for today
• ミックスイン
• 正格評価・遅延評価
• 変位指定
3Ⓒ Classmethod, Inc.
Topics for today
• ミックスイン
• 正格評価・遅延評価
• 変位指定
4Ⓒ Classmethod, Inc.
ミックスイン• ミックスイン
• 抽象インターフェイス
• デフォルト実装
• ミックスイン対象制限
5Ⓒ Classmethod, Inc.
ミックスイン
6Ⓒ Classmethod, Inc.
• ミックスイン(mix-in)とは?
クラスが「本来の型」に加えて、なんらかの任意の振る舞いを提供していることを宣言するために、クラスが実装する型
Bloch(2008) “Effective Java 2nd edition”
ミックスイン• ミックスイン
• 抽象インターフェイス
• デフォルト実装
• ミックスイン対象制限
7Ⓒ Classmethod, Inc.
抽象インターフェイス(Scala)
8Ⓒ Classmethod, Inc.
• traitは抽象インターフェイスをサポートしている
trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType}
Scala code
抽象インターフェイス(Scala)
9Ⓒ Classmethod, Inc.
• traitは抽象インターフェイスをサポートしている
trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType}
抽象型メンバー、定数、変数、メソッドが定義できるScala code
抽象インターフェイス(Swift)
10Ⓒ Classmethod, Inc.
• protocolは抽象インターフェイスをサポートしている protocol AbstractProtocol { typealias DataType var constant: DataType { get } var variable: DataType { get set } func method() -> DataType init(t: DataType) subscript(i: Int) -> DataType { get } func + (lhs: DataType, rhs: DataType) -> DataType}
Swift code
抽象インターフェイス(Swift)
11Ⓒ Classmethod, Inc.
• protocolは抽象インターフェイスをサポートしている protocol AbstractProtocol { typealias DataType var constant: DataType { get } var variable: DataType { get set } func method() -> DataType init(t: DataType) subscript(i: Int) -> DataType { get } func + (lhs: DataType, rhs: DataType) -> DataType} 抽象型メンバー、プロパティ、メソッド、イニシャライザ
サブスクリプト、演算子が定義できる
Swift code
ミックスイン• ミックスイン
• 抽象インターフェイス
• デフォルト実装
• ミックスイン対象制限
12Ⓒ Classmethod, Inc.
デフォルト実装(Scala)
13Ⓒ Classmethod, Inc.
• traitはデフォルト実装をサポートしている
trait AbstractTrait { type DataType = String val constant: DataType = “aa” var variable: DataType = “aaa” def method(): DataType = { “aaaa” }}
Scala code
デフォルト実装(Scala)
14Ⓒ Classmethod, Inc.
• traitはデフォルト実装をサポートしている
trait AbstractTrait { type DataType = String val constant: DataType = “aa” var variable: DataType = “aaa” def method(): DataType = { “aaaa” }}
デフォルトの実装をtraitの各メンバーに対して定義できるScala code
デフォルト実装(Swift 2.x)
15Ⓒ Classmethod, Inc.
• protocol extensionはデフォルト実装をサポートしている
extension AbstractProtocol { typealias DataType = String var constant: DataType { return “a” } func method() -> DataType { return “aa” }}
Swift code
デフォルト実装(Swift 2.x)
16Ⓒ Classmethod, Inc.
• protocol extensionはデフォルト実装をサポートしている
extension AbstractProtocol { typealias DataType = String var constant: DataType { return “a” } func method() -> DataType { return “aa” }}
デフォルトの実装をprotocolの各メンバーに対して定義できるSwift code
ミックスイン• ミックスイン
• 抽象インターフェイス
• デフォルト実装
• ミックスイン対象制限
17Ⓒ Classmethod, Inc.
ミックスイン対象制限(Scala)
18Ⓒ Classmethod, Inc.
• traitは自分型アノテーションで継承の対象になる型を限定できる
trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” }}
Scala code
ミックスイン対象制限(Scala)
19Ⓒ Classmethod, Inc.
• traitは自分型アノテーションで継承の対象になる型を限定できる
trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” }}
Scala code
ミックスインの対象になる型をSomeClassに限定できる →AbstractTraitはSomeClassと そのサブ型からしか継承できない
ミックスイン対象制限(Swift 2.x)
20Ⓒ Classmethod, Inc.
• protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる
extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” }}
Swift code
ミックスイン対象制限(Swift 2.x)
21Ⓒ Classmethod, Inc.
• protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる
extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” }}
デフォルトの実装を使える型はSomeClassとそのサブ型のみSwift code
ミックスイン対象制限(Swift 2.x)
22Ⓒ Classmethod, Inc.
• protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる
extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” }}
デフォルトの実装を使える型はSomeClassとそのサブ型のみSwift code
See also→ http://www.slideshare.net/UsrNameu1/swift2-protocol-extension
ミックスインのまとめ
23Ⓒ Classmethod, Inc.
Scala Swift
抽象インターフェイス
デフォルト実装
ミックスイン対象型への制約
trait protocol
trait protocol extension
traitでの 自分型アノテーション
protocol extensionでの Self への制約
Topics for today
• ミックスイン
• 正格評価・遅延評価
• 変位指定
24Ⓒ Classmethod, Inc.
正格評価・ 遅延評価• 正格評価・遅延評価
• lazy修飾子
• 遅延引数
• 遅延コレクション
25Ⓒ Classmethod, Inc.
正格評価・遅延評価
26Ⓒ Classmethod, Inc.
• 評価(evaluation) とは?
式から値を計算し、取り出す操作
正格評価・遅延評価
27Ⓒ Classmethod, Inc.
• 評価(evaluation) とは?
式から値を計算し、取り出す操作
let a = 1 + 1Swift code
正格評価・遅延評価
28Ⓒ Classmethod, Inc.
• 評価(evaluation) とは?
式から値を計算し、取り出す操作
let a = 1 + 1
1 + 1という式から2を計算し、取り出す
Swift code
正格評価・遅延評価
29Ⓒ Classmethod, Inc.
• 評価(evaluation) とは?
式から値を計算し、取り出す操作
let a = 1 + 1
1 + 1という式から2を計算し、取り出す
a という名前の定数に代入するSwift code
正格評価・遅延評価
30Ⓒ Classmethod, Inc.
• 正格評価(strict evaluation) とは?
評価結果が使用されるタイミングに関係なく 即時に行われる評価のこと
func add(a: Int, _ b: Int) -> Int { return a + b}struct Component { let c = add(1, 1)}
Swift code
正格評価・遅延評価
31Ⓒ Classmethod, Inc.
• 正格評価(strict evaluation) とは?
評価結果が使用されるタイミングに関係なく 即時に行われる評価のこと
func add(a: Int, _ b: Int) -> Int { return a + b}struct Component { let c = add(1, 1)}
cが用いられるタイミングに関係なく インスタンス生成時に評価される
Swift code
正格評価・遅延評価
32Ⓒ Classmethod, Inc.
• 遅延評価(strict evaluation) とは?
即時に行われず、後々必要になったタイミングで 行われる評価のこと
func add(a: Int, _ b: Int) -> Int { return a + b}struct LazyComponent { lazy var d = add(1, 2)}
Swift code
正格評価・遅延評価
33Ⓒ Classmethod, Inc.
• 遅延評価(strict evaluation) とは?
即時に行われず、後々必要になったタイミングで 行われる評価のこと
func add(a: Int, _ b: Int) -> Int { return a + b}struct LazyComponent { lazy var d = add(1, 2)} dが用いられるタイミングで評価される
Swift code
正格評価・ 遅延評価• 正格評価・遅延評価
• lazy修飾子
• 遅延引数
• 遅延コレクション
34Ⓒ Classmethod, Inc.
lazy修飾子(Scala)
35Ⓒ Classmethod, Inc.
• lazyをval(定数)の前につけると遅延評価になる
object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const
Scala code
lazy修飾子(Scala)
36Ⓒ Classmethod, Inc.
• lazyをval(定数)の前につけると遅延評価になる
object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const
Scala code
宣言時には評価されない
lazy修飾子(Scala)
37Ⓒ Classmethod, Inc.
• lazyをval(定数)の前につけると遅延評価になる
object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const
Scala code
宣言時には評価されない
アクセス時に評価され、 computed が出力される
lazy修飾子(Swift)
38Ⓒ Classmethod, Inc.
• lazyをvar(変数)の前につけると遅延評価になる
class LazyConstants { lazy var const: String = { print("computed") return "constant" }()}let constants = LazyConstants()let const = constants.const
Swift code
lazy修飾子(Swift)
39Ⓒ Classmethod, Inc.
• lazyをvar(変数)の前につけると遅延評価になる
class LazyConstants { lazy var const: String = { print("computed") return "constant" }()}let constants = LazyConstants()let const = constants.const
Swift code
インスタンス生成時には評価されない
lazy修飾子(Swift)
40Ⓒ Classmethod, Inc.
• lazyをvar(変数)の前につけると遅延評価になる
class LazyConstants { lazy var const: String = { print("computed") return "constant" }()}let constants = LazyConstants()let const = constants.const
Swift code
インスタンス生成時には評価されない
プロパティアクセス時に評価され、 computed が出力される
lazy修飾子(Swift)
41Ⓒ Classmethod, Inc.
• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる
let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count
Swift code
lazy修飾子(Swift)
42Ⓒ Classmethod, Inc.
• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる
let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count
Swift code
この時点では評価されない
lazy修飾子(Swift)
43Ⓒ Classmethod, Inc.
• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる
let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count
Swift code
この時点では評価されない
アクセス時に評価され、 computed が出力される
正格評価・ 遅延評価• 正格評価・遅延評価
• lazy修飾子
• 遅延引数
• 遅延コレクション
44Ⓒ Classmethod, Inc.
遅延引数(Scala)
45Ⓒ Classmethod, Inc.
• 名前渡しパラメーターは引数の評価を遅延する
val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError
byNameAssert(2 > 5)Scala code
遅延引数(Scala)
46Ⓒ Classmethod, Inc.
• 名前渡しパラメーターは引数の評価を遅延する
val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError
byNameAssert(2 > 5)Scala code
assertionsEnabled が真の時 初めて引数 pred を評価する
遅延引数(Scala)
47Ⓒ Classmethod, Inc.
• 名前渡しパラメーターは引数の評価を遅延する
val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError
byNameAssert(2 > 5)Scala code
assertionsEnabled が真の時 初めて引数 pred を評価する
評価は引数を渡すタイミングではなく、 byNameAssert内部の処理が走るタイミングで行われる
遅延引数(Swift)
48Ⓒ Classmethod, Inc.
• @autoclosureは引数の評価を遅延する
func myAnd( lhs: Bool, @autoclosure _ rhs: () -> Bool) -> Bool { if lhs { return rhs() } else { return false }}let result = myAnd(true, 1 < 2)
Swift code
遅延引数(Swift)
49Ⓒ Classmethod, Inc.
• @autoclosureは引数の評価を遅延する
func myAnd( lhs: Bool, @autoclosure _ rhs: () -> Bool) -> Bool { if lhs { return rhs() } else { return false }}let result = myAnd(true, 1 < 2)
Swift code
lhs が真の時初めて引数 rhs を評価する
遅延引数(Swift)
50Ⓒ Classmethod, Inc.
• @autoclosureは引数の評価を遅延する
func myAnd( lhs: Bool, @autoclosure _ rhs: () -> Bool) -> Bool { if lhs { return rhs() } else { return false }}let result = myAnd(true, 1 < 2)
Swift code
lhs が真の時初めて引数 rhs を評価する
評価は引数を渡すタイミングではなく、 myAnd内部の処理が走るタイミングで行われる
正格評価・ 遅延評価• 正格評価・遅延評価
• lazy修飾子
• 遅延引数
• 遅延コレクション
51Ⓒ Classmethod, Inc.
遅延コレクション(Scala)
52Ⓒ Classmethod, Inc.
• ビューはmap, filter等の変換メソッド処理を 遅延するコレクションを提供する
val vectorView = Vector(1 to 5: _*).view
val middleView = vectorView.map { x => println(x); x * 2 }middleView.map { _ + 3 }.force
Scala code
遅延コレクション(Scala)
53Ⓒ Classmethod, Inc.
• ビューはmap, filter等の変換メソッド処理を 遅延するコレクションを提供する
val vectorView = Vector(1 to 5: _*).view
val middleView = vectorView.map { x => println(x); x * 2 }middleView.map { _ + 3 }.force
Scala code
遅延コレクション生成
遅延コレクション(Scala)
54Ⓒ Classmethod, Inc.
• ビューはmap, filter等の変換メソッド処理を 遅延するコレクションを提供する
val vectorView = Vector(1 to 5: _*).view
val middleView = vectorView.map { x => println(x); x * 2 }middleView.map { _ + 3 }.force
Scala code
遅延コレクション生成
この時点では中の処理は実施されず 中間のVectorも作成されない
遅延コレクション(Scala)
55Ⓒ Classmethod, Inc.
• ビューはmap, filter等の変換メソッド処理を 遅延するコレクションを提供する
val vectorView = Vector(1 to 5: _*).view
val middleView = vectorView.map { x => println(x); x * 2 }middleView.map { _ + 3 }.force
Scala codeforceメソッドで正格コレクションに戻され、 それまでの変換メソッド処理が実施される。 (1 2 3 4 5が出力される)
遅延コレクション生成
この時点では中の処理は実施されず 中間のVectorも作成されない
遅延コレクション(Swift 2.x)
56Ⓒ Classmethod, Inc.
• LazySequenceプロトコルはmap, filter等の変換メソッド処理を遅延するコレクションを提供する
let lazyArr = [1,2,3,4,5].lazylet middleArr = lazyArr.map { x -> Int in print(x); return x * 2}let endArr = middleArr.map { x in x + 3 }for _ in endArr { }
Swift code
遅延コレクション(Swift 2.x)
57Ⓒ Classmethod, Inc.
• LazySequenceプロトコルはmap, filter等の変換メソッド処理を遅延するコレクションを提供する
let lazyArr = [1,2,3,4,5].lazylet middleArr = lazyArr.map { x -> Int in print(x); return x * 2}let endArr = middleArr.map { x in x + 3 }for _ in endArr { }
Swift code
遅延コレクション生成
遅延コレクション(Swift 2.x)
58Ⓒ Classmethod, Inc.
• LazySequenceプロトコルはmap, filter等の変換メソッド処理を遅延するコレクションを提供する
let lazyArr = [1,2,3,4,5].lazylet middleArr = lazyArr.map { x -> Int in print(x); return x * 2}let endArr = middleArr.map { x in x + 3 }for _ in endArr { }
Swift code
遅延コレクション生成
この時点では中の処理は 実施されず、中間のArrayも作成されない
遅延コレクション(Swift 2.x)
59Ⓒ Classmethod, Inc.
• LazySequenceプロトコルはmap, filter等の変換メソッド処理を遅延するコレクションを提供する
let lazyArr = [1,2,3,4,5].lazylet middleArr = lazyArr.map { x -> Int in print(x); return x * 2}let endArr = middleArr.map { x in x + 3 }for _ in endArr { }
Swift code必要になった時にそれまでの変換メソッド処理が実施される。 (1 2 3 4 5が出力される)
遅延コレクション生成
この時点では中の処理は 実施されず、中間のArrayも作成されない
遅延評価のまとめ
60Ⓒ Classmethod, Inc.
Scala Swift
lazy修飾子
遅延引数
遅延コレクション
つけると評価は遅延つけると評価は遅延 グローバル定数変数は つけなくても遅延
名前渡しパラメーター @autoclosure
コレクションに対して .viewで生成
force で正格評価
コレクションに対して .lazyで生成
必要なときに評価
Topics for today
• ミックスイン
• 正格評価・遅延評価
• 変位指定
61Ⓒ Classmethod, Inc.
変位指定• リスコフ置換原則
• 共変・反変
• 共変
• 反変
62Ⓒ Classmethod, Inc.
リスコフ置換原則
63Ⓒ Classmethod, Inc.
• リスコフ置換原則
Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.
Liskov, and Wing(1993) “A Behavioral Notion of Subtyping”
リスコフ置換原則
64Ⓒ Classmethod, Inc.
• リスコフ置換原則
T型のオブジェクトxに関して属性 Φ(x)が真
→ T型の派生型であるS型のオブジェクトyに関して 属性Φ(y)が真であるべき
リスコフ置換原則
65Ⓒ Classmethod, Inc.
• リスコフ置換原則
SがTの派生型なら T型の値が使える箇所でS型の値も使える
リスコフ置換原則
66Ⓒ Classmethod, Inc.
• リスコフ置換原則
SがTの派生型なら T型の値が使える箇所でS型の値も使える
「派生型」として満たされるべき原則 (必ずしも「継承」を意味しない)
変位指定• リスコフ置換原則
• 共変・反変
• 共変
• 反変
67Ⓒ Classmethod, Inc.
共変・反変
68Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
共変・反変
69Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数のない通常の型
共変・反変
70Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数のない通常の型
T S音楽は娯楽の「派生型」として置換可能
共変・反変
71Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数のない通常の型 →継承関係のみを気にすればうまくいく
T S音楽は娯楽の「派生型」として置換可能
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
72Ⓒ Classmethod, Inc.
共変・反変
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
73Ⓒ Classmethod, Inc.
共変・反変
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
74Ⓒ Classmethod, Inc.
メタルの作曲家は娯楽の提供者の 「派生型」として置換可能
T S
共変・反変
共変・反変
75Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
共変・反変
76Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
共変・反変
77Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数xのある型
TS有機物消費者は竹を食べるパンダの
「派生型」として置換可能
共変・反変
78Ⓒ Classmethod, Inc.
• ある型が別の型の派生型かどうかを判別する
型引数xのある型 →型引数の継承関係でうまく判断できないケースがある
TS有機物消費者は竹を食べるパンダの
「派生型」として置換可能
共変・反変
79Ⓒ Classmethod, Inc.
• 共変・反変で 型引数xのある型同士の派生型を判別する
共変(Covariant)型引数の場合
共変・反変
80Ⓒ Classmethod, Inc.
• 共変・反変で 型引数xのある型同士の派生型を判別する
共変(Covariant)型引数の場合 →型引数の派生順序を引き継ぐ
型引数xの派生順序
「xの提供者」の派生順序
共変・反変
81Ⓒ Classmethod, Inc.
• 共変・反変で 型引数xのある型同士の派生型を判別する
反変(Contravariant)型引数の場合
共変・反変
82Ⓒ Classmethod, Inc.
• 共変・反変で 型引数xのある型同士の派生型を判別する
反変(Contravariant)型引数の場合 →型引数の派生順序が反転する
型引数xの派生順序
「xの消費者」の派生順序
共変・反変
83Ⓒ Classmethod, Inc.
• 共変・反変で 型引数xのある型同士の派生型を判別する
反変(Contravariant)型引数の場合 →型引数の派生順序が反転する
型引数xの派生順序
「xの消費者」の派生順序
PECS (Producer extends Consumer super) と呼ばれる基準もある
共変・反変
84Ⓒ Classmethod, Inc.
• 共変・反変で型引数xのある型同士の派生型を判別する
型引数が複数あり、共変・反変が共存する場合
↓ ↑
T
S
U
V
共変・反変
85Ⓒ Classmethod, Inc.
• 共変・反変で型引数xのある型同士の派生型を判別する
型引数が複数あり、共変・反変が共存する場合
↓ ↑
T
S
U
V
TはSの派生型 VはUの派生型
共変・反変
86Ⓒ Classmethod, Inc.
• 共変・反変で型引数xのある型同士の派生型を判別する
型引数が複数あり、共変・反変が共存する場合
反変型引数 共変型引数
↓ ↑
T
S
U
V
TはSの派生型 VはUの派生型
共変・反変
87Ⓒ Classmethod, Inc.
• 共変・反変で型引数xのある型同士の派生型を判別する
型引数が複数あり、共変・反変が共存する場合
反変型引数 共変型引数
↓ ↑↑
T
S
U
V
TはSの派生型 VはUの派生型
[反変S, 共変V]は[反変T, 共変U]の派生型
共変・反変
88Ⓒ Classmethod, Inc.
• 共変・反変で型引数xのある型同士の派生型を判別する
型引数が複数あり、共変・反変が共存する場合 →共変型引数については派生順序を保持、 反変型引数については派生順序を逆転
反変型引数 共変型引数
↓ ↑↑
T
S
U
V
TはSの派生型 VはUの派生型
[反変S, 共変V]は[反変T, 共変U]の派生型
共変・反変は派生型についての判定材料を与える
89Ⓒ Classmethod, Inc.
変位指定• リスコフ置換原則
• 共変・反変
• 共変
• 反変
90Ⓒ Classmethod, Inc.
共変(Scala)
91Ⓒ Classmethod, Inc.
• +を型引数の前につけると共変となる
sealed abstract class List[+A] … var anyList: List[Any] = Nilval intList: List[Int] = List(2, 3, 4)anyList = intList
Scala code
共変(Scala)
92Ⓒ Classmethod, Inc.
• +を型引数の前につけると共変となる
sealed abstract class List[+A] … var anyList: List[Any] = Nilval intList: List[Int] = List(2, 3, 4)anyList = intList
Scala code派生順序は Any > Int
共変(Scala)
93Ⓒ Classmethod, Inc.
• +を型引数の前につけると共変となる
sealed abstract class List[+A] … var anyList: List[Any] = Nilval intList: List[Int] = List(2, 3, 4)anyList = intList
Scala code派生順序は Any > Int
型引数の派生順序が保存され、 List[Int] は List[Any]の派生型として扱える
共変(Objective-C)
94Ⓒ Classmethod, Inc.
• __covariantを型引数の前につけると共変となる
@interface NSArray<__covariant ObjectType>…NSArray<NSObject *> *anyArray = @[];NSArray<NSNumber *> *numberArray = @[@2, @3, @4];anyArray = numberArray;
Objective-C code
共変(Objective-C)
95Ⓒ Classmethod, Inc.
• __covariantを型引数の前につけると共変となる
@interface NSArray<__covariant ObjectType>…NSArray<NSObject *> *anyArray = @[];NSArray<NSNumber *> *numberArray = @[@2, @3, @4];anyArray = numberArray;
Objective-C code
派生順序は NSObject > NSNumber
共変(Objective-C)
96Ⓒ Classmethod, Inc.
• __covariantを型引数の前につけると共変となる
@interface NSArray<__covariant ObjectType>…NSArray<NSObject *> *anyArray = @[];NSArray<NSNumber *> *numberArray = @[@2, @3, @4];anyArray = numberArray;
Objective-C code
派生順序は NSObject > NSNumber
型引数の派生順序が保存され、 NSArray<NSNumber *>* は NSArray<NSObject *>* の派生型として扱える
共変(Swift)
97Ⓒ Classmethod, Inc.
• Array<T>はTについて共変
struct Array<T> …var anyArray: [Any] = []let intArray: [Int] = [2, 3, 4] anyArray = intArray
Swift code
共変(Swift)
98Ⓒ Classmethod, Inc.
• Array<T>はTについて共変
struct Array<T> …var anyArray: [Any] = []let intArray: [Int] = [2, 3, 4] anyArray = intArray
Swift code
派生順序は Any > Int
共変(Swift)
99Ⓒ Classmethod, Inc.
• Array<T>はTについて共変
struct Array<T> …var anyArray: [Any] = []let intArray: [Int] = [2, 3, 4] anyArray = intArray
Swift code
派生順序は Any > Int
型引数の派生順序が保存され、 Array<Int> は Array<Any> の派生型として扱える
共変(Swift)
100Ⓒ Classmethod, Inc.
• Array<T>はTについて共変
struct Array<T> …var anyArray: [Any] = []let intArray: [Int] = [2, 3, 4] anyArray = intArray
Swift code
派生順序は Any > Int
型引数の派生順序が保存され、 Array<Int> は Array<Any> の派生型として扱える
将来共変を表すためのキーワードが入るかも?(憶測
変位指定• リスコフ置換原則
• 共変・反変
• 共変
• 反変
101Ⓒ Classmethod, Inc.
反変(Scala)
102Ⓒ Classmethod, Inc.
• -を型引数の前につけると反変となる
class Consumer[-T] { def consume(p: T) = {}}var anyConsumer: Consumer[Any] = new Consumer[Any]()var intConsumer: Consumer[Int] = new Consumer[Int]()intConsumer = anyConsumer
Scala code
反変(Scala)
103Ⓒ Classmethod, Inc.
• -を型引数の前につけると反変となる
class Consumer[-T] { def consume(p: T) = {}}var anyConsumer: Consumer[Any] = new Consumer[Any]()var intConsumer: Consumer[Int] = new Consumer[Int]()intConsumer = anyConsumer
Scala code
派生順序は Any > Int
反変(Scala)
104Ⓒ Classmethod, Inc.
• -を型引数の前につけると反変となる
class Consumer[-T] { def consume(p: T) = {}}var anyConsumer: Consumer[Any] = new Consumer[Any]()var intConsumer: Consumer[Int] = new Consumer[Int]()intConsumer = anyConsumer
Scala code
派生順序は Any > Int
型引数の派生順序が逆転、 Consumer[Any] は Consumer[Int]の派生型として扱える
反変(Objective-C)
105Ⓒ Classmethod, Inc.
• __contravariantを型引数の前につけると反変となる
@interface Consumer<__contravariant Type> : NSObject- (void)consume:(Type)obj;@end@implementation Consumer- (void)consume:(id)obj {}@end
Objective-C code
反変(Objective-C)
106Ⓒ Classmethod, Inc.
• __contravariantを型引数の前につけると反変となる
@interface Consumer<__contravariant Type> : NSObject- (void)consume:(Type)obj;@end@implementation Consumer- (void)consume:(id)obj {}@end
Objective-C code実装の引数にはidを渡す
反変(Objective-C)
107Ⓒ Classmethod, Inc.
• __contravariantを型引数の前につけると反変となる
Consumer<NSObject *> *anyConsumer = [Consumer<NSObject *> new];Consumer<NSNumber *> *numberConsumer = [Consumer<NSNumber *> new];numberConsumer = anyConsumer;
Objective-C code
反変(Objective-C)
108Ⓒ Classmethod, Inc.
• __contravariantを型引数の前につけると反変となる
Consumer<NSObject *> *anyConsumer = [Consumer<NSObject *> new];Consumer<NSNumber *> *numberConsumer = [Consumer<NSNumber *> new];numberConsumer = anyConsumer;
Objective-C code
派生順序は NSObject > NSNumber
反変(Objective-C)
109Ⓒ Classmethod, Inc.
• __contravariantを型引数の前につけると反変となる
Consumer<NSObject *> *anyConsumer = [Consumer<NSObject *> new];Consumer<NSNumber *> *numberConsumer = [Consumer<NSNumber *> new];numberConsumer = anyConsumer;
Objective-C code
派生順序は NSObject > NSNumber
型引数の派生順序が逆転、 Consumer<NSObject *>* は Consumer<NSNumber *>* の派生型として扱える
反変(Swift 2.1)
110Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
func testVariance(foo:(Int) -> Any){ foo(1) }
func innerAnyInt(p1: Any) -> Int{ return 1 }func innerAnyAny(p1: Any) -> Any{ return 1 }func innerIntInt(p1: Int) -> Int{ return 1 }func innerIntAny(p1: Int) -> Any{ return 1 }
Swift code
http://www.uraimo.com/2015/09/29/Swift2.1-Function-Types-Conversion-Covariance-Contravariance/
反変(Swift 2.1)
111Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
func testVariance(foo:(Int) -> Any){ foo(1) }
func innerAnyInt(p1: Any) -> Int{ return 1 }func innerAnyAny(p1: Any) -> Any{ return 1 }func innerIntInt(p1: Int) -> Int{ return 1 }func innerIntAny(p1: Int) -> Any{ return 1 }
Swift code
引数にIntかその上位派生型、 返り値にAnyかその下位派生型をもつ関数を許容
http://www.uraimo.com/2015/09/29/Swift2.1-Function-Types-Conversion-Covariance-Contravariance/
反変(Swift 2.1)
112Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
func testVariance(foo:(Int) -> Any){ foo(1) }
func innerAnyInt(p1: Any) -> Int{ return 1 }func innerAnyAny(p1: Any) -> Any{ return 1 }func innerIntInt(p1: Int) -> Int{ return 1 }func innerIntAny(p1: Int) -> Any{ return 1 }
Swift code
引数にIntかその上位派生型、 返り値にAnyかその下位派生型をもつ関数を許容
http://www.uraimo.com/2015/09/29/Swift2.1-Function-Types-Conversion-Covariance-Contravariance/
これらの関数は引数がIntかその上位派生型Any 返り値がAnyかその下位派生型Int
反変(Swift 2.1)
113Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)
Swift code
反変(Swift 2.1)
114Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)
Swift code渡される関数の型は全て (Int) -> Any の派生型
反変(Swift 2.1)
115Ⓒ Classmethod, Inc.
• T -> S (関数の型)はTについて反変、Sについて共変
testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)
Swift code
将来反変を表すためのキーワードが入るかも?(憶測
渡される関数の型は全て (Int) -> Any の派生型
変位指定のまとめ
116Ⓒ Classmethod, Inc.
Scala ObjC Swift
共変
反変
[ +T ]
[ -T ]
<__covariant T>
<__contravariant T>
Array<T> が対応
T -> S の引数型 Tが対応
• Effective Java 第二版 項目18http://www.amazon.co.jp/dp/4621066056
• Scala スケーラブルプログラミング §19.3http://www.amazon.co.jp/dp/4844330845
• Java Generics: What is PECS? http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
117Ⓒ Classmethod, Inc.
References