117
Swift2.xを Scalaから見る 1 安達 勇一 クラスメソッド株式会社 2015年11月11日 Ⓒ Classmethod, Inc.

Swift2.x を Scala からみる

Embed Size (px)

Citation preview

Page 1: Swift2.x を Scala からみる

Swift2.xを Scalaから見る

1

安達 勇一 クラスメソッド株式会社2015年11月11日

Ⓒ Classmethod, Inc.

Page 2: Swift2.x を Scala からみる

2

安達 勇一• 2013/12 入社

• TwitterID: @UsrNameu1

• Github: https://github.com/UsrNameu1

• Blog: http://dev.classmethod.jp/author/yad

• ここ半年はサーバーサイドメイン

Page 3: Swift2.x を Scala からみる

Topics for today

• ミックスイン

• 正格評価・遅延評価

• 変位指定

3Ⓒ Classmethod, Inc.

Page 4: Swift2.x を Scala からみる

Topics for today

• ミックスイン

• 正格評価・遅延評価

• 変位指定

4Ⓒ Classmethod, Inc.

Page 5: Swift2.x を Scala からみる

ミックスイン• ミックスイン

• 抽象インターフェイス

• デフォルト実装

• ミックスイン対象制限

5Ⓒ Classmethod, Inc.

Page 6: Swift2.x を Scala からみる

ミックスイン

6Ⓒ Classmethod, Inc.

• ミックスイン(mix-in)とは?

クラスが「本来の型」に加えて、なんらかの任意の振る舞いを提供していることを宣言するために、クラスが実装する型

Bloch(2008) “Effective Java 2nd edition”

Page 7: Swift2.x を Scala からみる

ミックスイン• ミックスイン

• 抽象インターフェイス

• デフォルト実装

• ミックスイン対象制限

7Ⓒ Classmethod, Inc.

Page 8: Swift2.x を Scala からみる

抽象インターフェイス(Scala)

8Ⓒ Classmethod, Inc.

• traitは抽象インターフェイスをサポートしている

trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType}

Scala code

Page 9: Swift2.x を Scala からみる

抽象インターフェイス(Scala)

9Ⓒ Classmethod, Inc.

• traitは抽象インターフェイスをサポートしている

trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType}

抽象型メンバー、定数、変数、メソッドが定義できるScala code

Page 10: Swift2.x を Scala からみる

抽象インターフェイス(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

Page 11: Swift2.x を Scala からみる

抽象インターフェイス(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

Page 12: Swift2.x を Scala からみる

ミックスイン• ミックスイン

• 抽象インターフェイス

• デフォルト実装

• ミックスイン対象制限

12Ⓒ Classmethod, Inc.

Page 13: Swift2.x を Scala からみる

デフォルト実装(Scala)

13Ⓒ Classmethod, Inc.

• traitはデフォルト実装をサポートしている

trait AbstractTrait { type DataType = String val constant: DataType = “aa” var variable: DataType = “aaa” def method(): DataType = { “aaaa” }}

Scala code

Page 14: Swift2.x を Scala からみる

デフォルト実装(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

Page 15: Swift2.x を Scala からみる

デフォルト実装(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

Page 16: Swift2.x を Scala からみる

デフォルト実装(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

Page 17: Swift2.x を Scala からみる

ミックスイン• ミックスイン

• 抽象インターフェイス

• デフォルト実装

• ミックスイン対象制限

17Ⓒ Classmethod, Inc.

Page 18: Swift2.x を Scala からみる

ミックスイン対象制限(Scala)

18Ⓒ Classmethod, Inc.

• traitは自分型アノテーションで継承の対象になる型を限定できる

trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” }}

Scala code

Page 19: Swift2.x を Scala からみる

ミックスイン対象制限(Scala)

19Ⓒ Classmethod, Inc.

• traitは自分型アノテーションで継承の対象になる型を限定できる

trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” }}

Scala code

ミックスインの対象になる型をSomeClassに限定できる →AbstractTraitはSomeClassと  そのサブ型からしか継承できない

Page 20: Swift2.x を Scala からみる

ミックスイン対象制限(Swift 2.x)

20Ⓒ Classmethod, Inc.

• protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる

extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” }}

Swift code

Page 21: Swift2.x を Scala からみる

ミックスイン対象制限(Swift 2.x)

21Ⓒ Classmethod, Inc.

• protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる

extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” }}

デフォルトの実装を使える型はSomeClassとそのサブ型のみSwift code

Page 22: Swift2.x を Scala からみる

ミックスイン対象制限(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

Page 23: Swift2.x を Scala からみる

ミックスインのまとめ

23Ⓒ Classmethod, Inc.

Scala Swift

抽象インターフェイス

デフォルト実装

ミックスイン対象型への制約

trait protocol

trait protocol extension

traitでの 自分型アノテーション

protocol extensionでの Self への制約

Page 24: Swift2.x を Scala からみる

Topics for today

• ミックスイン

• 正格評価・遅延評価

• 変位指定

24Ⓒ Classmethod, Inc.

Page 25: Swift2.x を Scala からみる

正格評価・ 遅延評価• 正格評価・遅延評価

• lazy修飾子

• 遅延引数

• 遅延コレクション

25Ⓒ Classmethod, Inc.

Page 26: Swift2.x を Scala からみる

正格評価・遅延評価

26Ⓒ Classmethod, Inc.

• 評価(evaluation) とは?

式から値を計算し、取り出す操作

Page 27: Swift2.x を Scala からみる

正格評価・遅延評価

27Ⓒ Classmethod, Inc.

• 評価(evaluation) とは?

式から値を計算し、取り出す操作

let a = 1 + 1Swift code

Page 28: Swift2.x を Scala からみる

正格評価・遅延評価

28Ⓒ Classmethod, Inc.

• 評価(evaluation) とは?

式から値を計算し、取り出す操作

let a = 1 + 1

1 + 1という式から2を計算し、取り出す

Swift code

Page 29: Swift2.x を Scala からみる

正格評価・遅延評価

29Ⓒ Classmethod, Inc.

• 評価(evaluation) とは?

式から値を計算し、取り出す操作

let a = 1 + 1

1 + 1という式から2を計算し、取り出す

a という名前の定数に代入するSwift code

Page 30: Swift2.x を Scala からみる

正格評価・遅延評価

30Ⓒ Classmethod, Inc.

• 正格評価(strict evaluation) とは?

 評価結果が使用されるタイミングに関係なく  即時に行われる評価のこと

func add(a: Int, _ b: Int) -> Int { return a + b}struct Component { let c = add(1, 1)}

Swift code

Page 31: Swift2.x を Scala からみる

正格評価・遅延評価

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

Page 32: Swift2.x を Scala からみる

正格評価・遅延評価

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

Page 33: Swift2.x を Scala からみる

正格評価・遅延評価

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

Page 34: Swift2.x を Scala からみる

正格評価・ 遅延評価• 正格評価・遅延評価

• lazy修飾子

• 遅延引数

• 遅延コレクション

34Ⓒ Classmethod, Inc.

Page 35: Swift2.x を Scala からみる

lazy修飾子(Scala)

35Ⓒ Classmethod, Inc.

• lazyをval(定数)の前につけると遅延評価になる

  object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const

Scala code

Page 36: Swift2.x を Scala からみる

lazy修飾子(Scala)

36Ⓒ Classmethod, Inc.

• lazyをval(定数)の前につけると遅延評価になる

  object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const

Scala code

宣言時には評価されない

Page 37: Swift2.x を Scala からみる

lazy修飾子(Scala)

37Ⓒ Classmethod, Inc.

• lazyをval(定数)の前につけると遅延評価になる

  object LazyConstants { lazy val const: String = { println("computed") "constant" }}val a = LazyConstants.const

Scala code

宣言時には評価されない

アクセス時に評価され、 computed が出力される

Page 38: Swift2.x を Scala からみる

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

Page 39: Swift2.x を Scala からみる

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

インスタンス生成時には評価されない

Page 40: Swift2.x を Scala からみる

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 が出力される

Page 41: Swift2.x を Scala からみる

lazy修飾子(Swift)

41Ⓒ Classmethod, Inc.

• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる

  let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count

Swift code

Page 42: Swift2.x を Scala からみる

lazy修飾子(Swift)

42Ⓒ Classmethod, Inc.

• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる

  let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count

Swift code

この時点では評価されない

Page 43: Swift2.x を Scala からみる

lazy修飾子(Swift)

43Ⓒ Classmethod, Inc.

• グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる

  let someConst: String = { print("computed") return "constant"}()let length = someConst.utf8.count

Swift code

この時点では評価されない

アクセス時に評価され、 computed が出力される

Page 44: Swift2.x を Scala からみる

正格評価・ 遅延評価• 正格評価・遅延評価

• lazy修飾子

• 遅延引数

• 遅延コレクション

44Ⓒ Classmethod, Inc.

Page 45: Swift2.x を Scala からみる

遅延引数(Scala)

45Ⓒ Classmethod, Inc.

• 名前渡しパラメーターは引数の評価を遅延する

  val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError

byNameAssert(2 > 5)Scala code

Page 46: Swift2.x を Scala からみる

遅延引数(Scala)

46Ⓒ Classmethod, Inc.

• 名前渡しパラメーターは引数の評価を遅延する

  val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError

byNameAssert(2 > 5)Scala code

assertionsEnabled が真の時 初めて引数 pred を評価する

Page 47: Swift2.x を Scala からみる

遅延引数(Scala)

47Ⓒ Classmethod, Inc.

• 名前渡しパラメーターは引数の評価を遅延する

  val assertionsEnabled = truedef byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError

byNameAssert(2 > 5)Scala code

assertionsEnabled が真の時 初めて引数 pred を評価する

評価は引数を渡すタイミングではなく、 byNameAssert内部の処理が走るタイミングで行われる

Page 48: Swift2.x を Scala からみる

遅延引数(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

Page 49: Swift2.x を Scala からみる

遅延引数(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 を評価する

Page 50: Swift2.x を Scala からみる

遅延引数(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内部の処理が走るタイミングで行われる

Page 51: Swift2.x を Scala からみる

正格評価・ 遅延評価• 正格評価・遅延評価

• lazy修飾子

• 遅延引数

• 遅延コレクション

51Ⓒ Classmethod, Inc.

Page 52: Swift2.x を Scala からみる

遅延コレクション(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

Page 53: Swift2.x を Scala からみる

遅延コレクション(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

遅延コレクション生成

Page 54: Swift2.x を Scala からみる

遅延コレクション(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も作成されない

Page 55: Swift2.x を Scala からみる

遅延コレクション(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も作成されない

Page 56: Swift2.x を Scala からみる

遅延コレクション(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

Page 57: Swift2.x を Scala からみる

遅延コレクション(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

遅延コレクション生成

Page 58: Swift2.x を Scala からみる

遅延コレクション(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も作成されない

Page 59: Swift2.x を Scala からみる

遅延コレクション(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も作成されない

Page 60: Swift2.x を Scala からみる

遅延評価のまとめ

60Ⓒ Classmethod, Inc.

Scala Swift

lazy修飾子

遅延引数

遅延コレクション

つけると評価は遅延つけると評価は遅延 グローバル定数変数は つけなくても遅延

名前渡しパラメーター @autoclosure

コレクションに対して .viewで生成

force で正格評価

コレクションに対して .lazyで生成

必要なときに評価

Page 61: Swift2.x を Scala からみる

Topics for today

• ミックスイン

• 正格評価・遅延評価

• 変位指定

61Ⓒ Classmethod, Inc.

Page 62: Swift2.x を Scala からみる

変位指定• リスコフ置換原則

• 共変・反変

• 共変

• 反変

62Ⓒ Classmethod, Inc.

Page 63: Swift2.x を Scala からみる

リスコフ置換原則

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”

Page 64: Swift2.x を Scala からみる

リスコフ置換原則

64Ⓒ Classmethod, Inc.

• リスコフ置換原則

  T型のオブジェクトxに関して属性 Φ(x)が真

→ T型の派生型であるS型のオブジェクトyに関して 属性Φ(y)が真であるべき

Page 65: Swift2.x を Scala からみる

リスコフ置換原則

65Ⓒ Classmethod, Inc.

• リスコフ置換原則

 SがTの派生型なら T型の値が使える箇所でS型の値も使える

Page 66: Swift2.x を Scala からみる

リスコフ置換原則

66Ⓒ Classmethod, Inc.

• リスコフ置換原則

 SがTの派生型なら T型の値が使える箇所でS型の値も使える

「派生型」として満たされるべき原則 (必ずしも「継承」を意味しない)

Page 67: Swift2.x を Scala からみる

変位指定• リスコフ置換原則

• 共変・反変

• 共変

• 反変

67Ⓒ Classmethod, Inc.

Page 68: Swift2.x を Scala からみる

共変・反変

68Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs

Page 69: Swift2.x を Scala からみる

共変・反変

69Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数のない通常の型 

Page 70: Swift2.x を Scala からみる

共変・反変

70Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数のない通常の型 

T S音楽は娯楽の「派生型」として置換可能

Page 71: Swift2.x を Scala からみる

共変・反変

71Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数のない通常の型  →継承関係のみを気にすればうまくいく

T S音楽は娯楽の「派生型」として置換可能

Page 72: Swift2.x を Scala からみる

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

72Ⓒ Classmethod, Inc.

共変・反変

Page 73: Swift2.x を Scala からみる

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

73Ⓒ Classmethod, Inc.

共変・反変

Page 74: Swift2.x を Scala からみる

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

74Ⓒ Classmethod, Inc.

メタルの作曲家は娯楽の提供者の 「派生型」として置換可能

T S

共変・反変

Page 75: Swift2.x を Scala からみる

共変・反変

75Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

Page 76: Swift2.x を Scala からみる

共変・反変

76Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

Page 77: Swift2.x を Scala からみる

共変・反変

77Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数xのある型 

TS有機物消費者は竹を食べるパンダの

「派生型」として置換可能

Page 78: Swift2.x を Scala からみる

共変・反変

78Ⓒ Classmethod, Inc.

• ある型が別の型の派生型かどうかを判別する

型引数xのある型  →型引数の継承関係でうまく判断できないケースがある

TS有機物消費者は竹を食べるパンダの

「派生型」として置換可能

Page 79: Swift2.x を Scala からみる

共変・反変

79Ⓒ Classmethod, Inc.

• 共変・反変で 型引数xのある型同士の派生型を判別する

共変(Covariant)型引数の場合

 

Page 80: Swift2.x を Scala からみる

共変・反変

80Ⓒ Classmethod, Inc.

• 共変・反変で 型引数xのある型同士の派生型を判別する

共変(Covariant)型引数の場合 →型引数の派生順序を引き継ぐ

 

型引数xの派生順序

「xの提供者」の派生順序

Page 81: Swift2.x を Scala からみる

共変・反変

81Ⓒ Classmethod, Inc.

• 共変・反変で 型引数xのある型同士の派生型を判別する

反変(Contravariant)型引数の場合

 

Page 82: Swift2.x を Scala からみる

共変・反変

82Ⓒ Classmethod, Inc.

• 共変・反変で 型引数xのある型同士の派生型を判別する

反変(Contravariant)型引数の場合 →型引数の派生順序が反転する

 

型引数xの派生順序

「xの消費者」の派生順序

Page 83: Swift2.x を Scala からみる

共変・反変

83Ⓒ Classmethod, Inc.

• 共変・反変で 型引数xのある型同士の派生型を判別する

反変(Contravariant)型引数の場合 →型引数の派生順序が反転する

 

型引数xの派生順序

「xの消費者」の派生順序

PECS (Producer extends Consumer super) と呼ばれる基準もある

Page 84: Swift2.x を Scala からみる

共変・反変

84Ⓒ Classmethod, Inc.

• 共変・反変で型引数xのある型同士の派生型を判別する

型引数が複数あり、共変・反変が共存する場合

↓ ↑

T

S

U

V

Page 85: Swift2.x を Scala からみる

共変・反変

85Ⓒ Classmethod, Inc.

• 共変・反変で型引数xのある型同士の派生型を判別する

型引数が複数あり、共変・反変が共存する場合

↓ ↑

T

S

U

V

TはSの派生型 VはUの派生型

Page 86: Swift2.x を Scala からみる

共変・反変

86Ⓒ Classmethod, Inc.

• 共変・反変で型引数xのある型同士の派生型を判別する

型引数が複数あり、共変・反変が共存する場合

反変型引数 共変型引数

↓ ↑

T

S

U

V

TはSの派生型 VはUの派生型

Page 87: Swift2.x を Scala からみる

共変・反変

87Ⓒ Classmethod, Inc.

• 共変・反変で型引数xのある型同士の派生型を判別する

型引数が複数あり、共変・反変が共存する場合

反変型引数 共変型引数

↓ ↑↑

T

S

U

V

TはSの派生型 VはUの派生型

[反変S, 共変V]は[反変T, 共変U]の派生型

Page 88: Swift2.x を Scala からみる

共変・反変

88Ⓒ Classmethod, Inc.

• 共変・反変で型引数xのある型同士の派生型を判別する

型引数が複数あり、共変・反変が共存する場合 →共変型引数については派生順序を保持、  反変型引数については派生順序を逆転

反変型引数 共変型引数

↓ ↑↑

T

S

U

V

TはSの派生型 VはUの派生型

[反変S, 共変V]は[反変T, 共変U]の派生型

Page 89: Swift2.x を Scala からみる

共変・反変は派生型についての判定材料を与える

89Ⓒ Classmethod, Inc.

Page 90: Swift2.x を Scala からみる

変位指定• リスコフ置換原則

• 共変・反変

• 共変

• 反変

90Ⓒ Classmethod, Inc.

Page 91: Swift2.x を Scala からみる

共変(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

Page 92: Swift2.x を Scala からみる

共変(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

Page 93: Swift2.x を Scala からみる

共変(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]の派生型として扱える

Page 94: Swift2.x を Scala からみる

共変(Objective-C)

94Ⓒ Classmethod, Inc.

• __covariantを型引数の前につけると共変となる

  @interface NSArray<__covariant ObjectType>…NSArray<NSObject *> *anyArray = @[];NSArray<NSNumber *> *numberArray = @[@2, @3, @4];anyArray = numberArray;

Objective-C code

Page 95: Swift2.x を Scala からみる

共変(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

Page 96: Swift2.x を Scala からみる

共変(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 *>* の派生型として扱える

Page 97: Swift2.x を Scala からみる

共変(Swift)

97Ⓒ Classmethod, Inc.

• Array<T>はTについて共変

  struct Array<T> …var anyArray: [Any] = []let intArray: [Int] = [2, 3, 4] anyArray = intArray

Swift code

Page 98: Swift2.x を Scala からみる

共変(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

Page 99: Swift2.x を Scala からみる

共変(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> の派生型として扱える

Page 100: Swift2.x を Scala からみる

共変(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> の派生型として扱える

将来共変を表すためのキーワードが入るかも?(憶測

Page 101: Swift2.x を Scala からみる

変位指定• リスコフ置換原則

• 共変・反変

• 共変

• 反変

101Ⓒ Classmethod, Inc.

Page 102: Swift2.x を Scala からみる

反変(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

Page 103: Swift2.x を Scala からみる

反変(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

Page 104: Swift2.x を Scala からみる

反変(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]の派生型として扱える

Page 105: Swift2.x を Scala からみる

反変(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

Page 106: Swift2.x を Scala からみる

反変(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を渡す

Page 107: Swift2.x を Scala からみる

反変(Objective-C)

107Ⓒ Classmethod, Inc.

• __contravariantを型引数の前につけると反変となる

  Consumer<NSObject *> *anyConsumer = [Consumer<NSObject *> new];Consumer<NSNumber *> *numberConsumer = [Consumer<NSNumber *> new];numberConsumer = anyConsumer;

Objective-C code

Page 108: Swift2.x を Scala からみる

反変(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

Page 109: Swift2.x を Scala からみる

反変(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 *>* の派生型として扱える

Page 110: Swift2.x を Scala からみる

反変(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/

Page 111: Swift2.x を Scala からみる

反変(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/

Page 112: Swift2.x を Scala からみる

反変(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

Page 113: Swift2.x を Scala からみる

反変(Swift 2.1)

113Ⓒ Classmethod, Inc.

• T -> S (関数の型)はTについて反変、Sについて共変

  testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)

Swift code

Page 114: Swift2.x を Scala からみる

反変(Swift 2.1)

114Ⓒ Classmethod, Inc.

• T -> S (関数の型)はTについて反変、Sについて共変

  testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)

Swift code渡される関数の型は全て (Int) -> Any の派生型

Page 115: Swift2.x を Scala からみる

反変(Swift 2.1)

115Ⓒ Classmethod, Inc.

• T -> S (関数の型)はTについて反変、Sについて共変

  testVariance(innerIntAny)testVariance(innerAnyInt)testVariance(innerAnyAny)testVariance(innerIntInt)

Swift code

将来反変を表すためのキーワードが入るかも?(憶測

渡される関数の型は全て (Int) -> Any の派生型

Page 116: Swift2.x を Scala からみる

変位指定のまとめ

116Ⓒ Classmethod, Inc.

Scala ObjC Swift

共変

反変

[ +T ]

[ -T ]

<__covariant T>

<__contravariant T>

Array<T> が対応

T -> S の引数型 Tが対応

Page 117: Swift2.x を Scala からみる

• 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