Swift2.x を Scala からみる

2,416 views

Published on

2015/11/11 「iOS 9 Bootcamp」 発表資料

Published in: Engineering

Swift2.x を Scala からみる

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

×