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 + 1
Swift 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 = true
def byNameAssert(pred: => Boolean) =
if (assertionsEnabled && !pred)
throw new AssertionError
byNameAssert(2 > 5)
Scala code
遅延引数(Scala)
46Ⓒ Classmethod, Inc.
• 名前渡しパラメーターは引数の評価を遅延する
 
val assertionsEnabled = true
def byNameAssert(pred: => Boolean) =
if (assertionsEnabled && !pred)
throw new AssertionError
byNameAssert(2 > 5)
Scala code
assertionsEnabled が真の時
初めて引数 pred を評価する
遅延引数(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内部の処理が走るタイミングで行われる
遅延引数(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].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
遅延コレクション(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
遅延コレクション生成
遅延コレクション(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も作成されない
遅延コレクション(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Ⓒ 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] = Nil
val intList: List[Int] = List(2, 3, 4)
anyList = intList
Scala code
共変(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
共変(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]の派生型として扱える
共変(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 第二版 項目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

Swift2.x を Scala からみる

  • 1.
  • 2.
    2 安達 勇一 • 2013/12 入社 •TwitterID: @UsrNameu1 • Github: https://github.com/ UsrNameu1 • Blog: http://dev.classmethod.jp/ author/yad • ここ半年はサーバーサイドメイン
  • 3.
    Topics for today •ミックスイン • 正格評価・遅延評価 • 変位指定 3Ⓒ Classmethod, Inc.
  • 4.
    Topics for today •ミックスイン • 正格評価・遅延評価 • 変位指定 4Ⓒ Classmethod, Inc.
  • 5.
    ミックスイン • ミックスイン • 抽象インターフェイス •デフォルト実装 • ミックスイン対象制限 5Ⓒ Classmethod, Inc.
  • 6.
    ミックスイン 6Ⓒ Classmethod, Inc. •ミックスイン(mix-in)とは? クラスが「本来の型」に加えて、なんらかの任意の振 る舞いを提供していることを宣言するために、クラスが 実装する型 Bloch(2008)  Effective Java 2nd edition
  • 7.
    ミックスイン • ミックスイン • 抽象インターフェイス •デフォルト実装 • ミックスイン対象制限 7Ⓒ Classmethod, Inc.
  • 8.
    抽象インターフェイス(Scala) 8Ⓒ Classmethod, Inc. •traitは抽象インターフェイスをサポートしている trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType } Scala code
  • 9.
    抽象インターフェイス(Scala) 9Ⓒ Classmethod, Inc. •traitは抽象インターフェイスをサポートしている trait AbstractTrait { type DataType val constant: DataType var variable: DataType def method(): DataType } 抽象型メンバー、定数、変数、メソッドが定義できる Scala code
  • 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.
    抽象インターフェイス(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Ⓒ Classmethod, Inc.
  • 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.
    デフォルト実装(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.
    デフォルト実装(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.
    デフォルト実装(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Ⓒ Classmethod, Inc.
  • 18.
    ミックスイン対象制限(Scala) 18Ⓒ Classmethod, Inc. •traitは自分型アノテーションで継承の対象になる型を 限定できる trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” } } Scala code
  • 19.
    ミックスイン対象制限(Scala) 19Ⓒ Classmethod, Inc. •traitは自分型アノテーションで継承の対象になる型を 限定できる trait AbstractTrait { self: SomeClass => def method(): String = { “aaaa” } } Scala code ミックスインの対象になる型をSomeClassに限定できる →AbstractTraitはSomeClassと  そのサブ型からしか継承できない
  • 20.
    ミックスイン対象制限(Swift 2.x) 20Ⓒ Classmethod,Inc. • protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” } } Swift code
  • 21.
    ミックスイン対象制限(Swift 2.x) 21Ⓒ Classmethod,Inc. • protocol extensionのSelfへの制約によって デフォルト実装が使える継承の対象となる型を制限できる extension AbstractProtocol where Self: SomeClass { func method() -> String { return “aa” } } デフォルトの実装を使える型はSomeClassとそのサブ型のみ Swift code
  • 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Ⓒ Classmethod, Inc. ScalaSwift 抽象インターフェイス デフォルト実装 ミックスイン対象型への制約 trait protocol trait protocol extension traitでの 自分型アノテーション protocol extensionでの Self への制約
  • 24.
    Topics for today •ミックスイン • 正格評価・遅延評価 • 変位指定 24Ⓒ Classmethod, Inc.
  • 25.
    正格評価・ 遅延評価 • 正格評価・遅延評価 • lazy修飾子 •遅延引数 • 遅延コレクション 25Ⓒ Classmethod, Inc.
  • 26.
    正格評価・遅延評価 26Ⓒ Classmethod, Inc. •評価(evaluation) とは? 式から値を計算し、取り出す操作
  • 27.
    正格評価・遅延評価 27Ⓒ Classmethod, Inc. •評価(evaluation) とは? 式から値を計算し、取り出す操作 let a = 1 + 1 Swift code
  • 28.
    正格評価・遅延評価 28Ⓒ Classmethod, Inc. •評価(evaluation) とは? 式から値を計算し、取り出す操作 let a = 1 + 1 1 + 1という式から2を計算し、取り出す Swift code
  • 29.
    正格評価・遅延評価 29Ⓒ Classmethod, Inc. •評価(evaluation) とは? 式から値を計算し、取り出す操作 let a = 1 + 1 1 + 1という式から2を計算し、取り出す a という名前の定数に代入する Swift code
  • 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Ⓒ 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Ⓒ 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Ⓒ 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.
    正格評価・ 遅延評価 • 正格評価・遅延評価 • lazy修飾子 •遅延引数 • 遅延コレクション 34Ⓒ Classmethod, Inc.
  • 35.
    lazy修飾子(Scala) 35Ⓒ Classmethod, Inc. •lazyをval(定数)の前につけると遅延評価になる   object LazyConstants { lazy val const: String = { println("computed") "constant" } } val a = LazyConstants.const Scala code
  • 36.
    lazy修飾子(Scala) 36Ⓒ Classmethod, Inc. •lazyをval(定数)の前につけると遅延評価になる   object LazyConstants { lazy val const: String = { println("computed") "constant" } } val a = LazyConstants.const Scala code 宣言時には評価されない
  • 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.
    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.
    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.
    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.
    lazy修飾子(Swift) 41Ⓒ Classmethod, Inc. •グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる   let someConst: String = { print("computed") return "constant" }() let length = someConst.utf8.count Swift code
  • 42.
    lazy修飾子(Swift) 42Ⓒ Classmethod, Inc. •グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる   let someConst: String = { print("computed") return "constant" }() let length = someConst.utf8.count Swift code この時点では評価されない
  • 43.
    lazy修飾子(Swift) 43Ⓒ Classmethod, Inc. •グローバル変数、定数はlazy修飾子をつけなくても 自動的に遅延評価になる   let someConst: String = { print("computed") return "constant" }() let length = someConst.utf8.count Swift code この時点では評価されない アクセス時に評価され、 computed が出力される
  • 44.
    正格評価・ 遅延評価 • 正格評価・遅延評価 • lazy修飾子 •遅延引数 • 遅延コレクション 44Ⓒ Classmethod, Inc.
  • 45.
    遅延引数(Scala) 45Ⓒ Classmethod, Inc. •名前渡しパラメーターは引数の評価を遅延する   val assertionsEnabled = true def byNameAssert(pred: => Boolean) = if (assertionsEnabled && !pred) throw new AssertionError byNameAssert(2 > 5) Scala code
  • 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.
    遅延引数(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.
    遅延引数(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.
    遅延引数(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.
    遅延引数(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.
    正格評価・ 遅延評価 • 正格評価・遅延評価 • lazy修飾子 •遅延引数 • 遅延コレクション 51Ⓒ Classmethod, Inc.
  • 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.
    遅延コレクション(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.
    遅延コレクション(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.
    遅延コレクション(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.
    遅延コレクション(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.
    遅延コレクション(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.
    遅延コレクション(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.
    遅延コレクション(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Ⓒ Classmethod, Inc. ScalaSwift lazy修飾子 遅延引数 遅延コレクション つけると評価は遅延 つけると評価は遅延 グローバル定数変数は つけなくても遅延 名前渡しパラメーター @autoclosure コレクションに対して .viewで生成 force で正格評価 コレクションに対して .lazyで生成 必要なときに評価
  • 61.
    Topics for today •ミックスイン • 正格評価・遅延評価 • 変位指定 61Ⓒ Classmethod, Inc.
  • 62.
  • 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Ⓒ Classmethod, Inc. •リスコフ置換原則   T型のオブジェクトxに関して属性 Φ(x)が真 → T型の派生型であるS型のオブジェクトyに関して 属性Φ(y)が真であるべき
  • 65.
    リスコフ置換原則 65Ⓒ Classmethod, Inc. •リスコフ置換原則  SがTの派生型なら T型の値が使える箇所でS型の値も使える
  • 66.
    リスコフ置換原則 66Ⓒ Classmethod, Inc. •リスコフ置換原則  SがTの派生型なら T型の値が使える箇所でS型の値も使える 「派生型」として満たされるべき原則 (必ずしも「継承」を意味しない)
  • 67.
  • 68.
    共変・反変 68Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
  • 69.
    共変・反変 69Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数のない通常の型 
  • 70.
    共変・反変 70Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数のない通常の型  T S 音楽は娯楽の「派生型」として置換可能
  • 71.
    共変・反変 71Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数のない通常の型  →継承関係のみを気にすればうまくいく T S 音楽は娯楽の「派生型」として置換可能
  • 72.
  • 73.
  • 74.
    • ある型が別の型の派生型かどうかを判別する 型引数xのある型  74Ⓒ Classmethod,Inc. メタルの作曲家は娯楽の提供者の 「派生型」として置換可能 T S 共変・反変
  • 75.
    共変・反変 75Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数xのある型 
  • 76.
    共変・反変 76Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数xのある型 
  • 77.
    共変・反変 77Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数xのある型  TS 有機物消費者は竹を食べるパンダの 「派生型」として置換可能
  • 78.
    共変・反変 78Ⓒ Classmethod, Inc. •ある型が別の型の派生型かどうかを判別する 型引数xのある型  →型引数の継承関係でうまく判断できないケースがある TS 有機物消費者は竹を食べるパンダの 「派生型」として置換可能
  • 79.
    共変・反変 79Ⓒ Classmethod, Inc. •共変・反変で 型引数xのある型同士の派生型を判別する 共変(Covariant)型引数の場合  
  • 80.
    共変・反変 80Ⓒ Classmethod, Inc. •共変・反変で 型引数xのある型同士の派生型を判別する 共変(Covariant)型引数の場合 →型引数の派生順序を引き継ぐ   型引数xの派生順序 「xの提供者」の派生順序
  • 81.
    共変・反変 81Ⓒ Classmethod, Inc. •共変・反変で 型引数xのある型同士の派生型を判別する 反変(Contravariant)型引数の場合  
  • 82.
    共変・反変 82Ⓒ Classmethod, Inc. •共変・反変で 型引数xのある型同士の派生型を判別する 反変(Contravariant)型引数の場合 →型引数の派生順序が反転する   型引数xの派生順序 「xの消費者」の派生順序
  • 83.
    共変・反変 83Ⓒ Classmethod, Inc. •共変・反変で 型引数xのある型同士の派生型を判別する 反変(Contravariant)型引数の場合 →型引数の派生順序が反転する   型引数xの派生順序 「xの消費者」の派生順序 PECS (Producer extends Consumer super) と呼ばれる基準もある
  • 84.
    共変・反変 84Ⓒ Classmethod, Inc. •共変・反変で型引数xのある型同士の派生型を判別する 型引数が複数あり、共変・反変が共存する場合 ↓ ↑ T S U V
  • 85.
    共変・反変 85Ⓒ Classmethod, Inc. •共変・反変で型引数xのある型同士の派生型を判別する 型引数が複数あり、共変・反変が共存する場合 ↓ ↑ T S U V TはSの派生型 VはUの派生型
  • 86.
    共変・反変 86Ⓒ Classmethod, Inc. •共変・反変で型引数xのある型同士の派生型を判別する 型引数が複数あり、共変・反変が共存する場合 反変型引数 共変型引数 ↓ ↑ T S U V TはSの派生型 VはUの派生型
  • 87.
    共変・反変 87Ⓒ Classmethod, Inc. •共変・反変で型引数xのある型同士の派生型を判別する 型引数が複数あり、共変・反変が共存する場合 反変型引数 共変型引数 ↓ ↑↑ T S U V TはSの派生型 VはUの派生型 [反変S, 共変V]は[反変T, 共変U]の派生型
  • 88.
    共変・反変 88Ⓒ Classmethod, Inc. •共変・反変で型引数xのある型同士の派生型を判別する 型引数が複数あり、共変・反変が共存する場合 →共変型引数については派生順序を保持、  反変型引数については派生順序を逆転 反変型引数 共変型引数 ↓ ↑↑ T S U V TはSの派生型 VはUの派生型 [反変S, 共変V]は[反変T, 共変U]の派生型
  • 89.
  • 90.
  • 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.
    共変(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.
    共変(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.
    共変(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.
    共変(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.
    共変(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.
    共変(Swift) 97Ⓒ Classmethod, Inc. •Array<T>はTについて共変   struct Array<T> … var anyArray: [Any] = [] let intArray: [Int] = [2, 3, 4] anyArray = intArray Swift code
  • 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.
    共変(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.
    共変(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.
  • 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.
    反変(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.
    反変(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.
    反変(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.
    反変(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.
    反変(Objective-C) 107Ⓒ Classmethod, Inc. •__contravariantを型引数の前につけると反変となる   Consumer<NSObject *> *anyConsumer = [Consumer<NSObject *> new]; Consumer<NSNumber *> *numberConsumer = [Consumer<NSNumber *> new]; numberConsumer = anyConsumer; Objective-C code
  • 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.
    反変(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.
    反変(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.
    反変(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.
    反変(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.
    反変(Swift 2.1) 113Ⓒ Classmethod,Inc. • T -> S (関数の型)はTについて反変、Sについて共変   testVariance(innerIntAny) testVariance(innerAnyInt) testVariance(innerAnyAny) testVariance(innerIntInt) Swift code
  • 114.
    反変(Swift 2.1) 114Ⓒ Classmethod,Inc. • T -> S (関数の型)はTについて反変、Sについて共変   testVariance(innerIntAny) testVariance(innerAnyInt) testVariance(innerAnyAny) testVariance(innerIntInt) Swift code 渡される関数の型は全て (Int) -> Any の派生型
  • 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Ⓒ Classmethod, Inc. ScalaObjC Swift 共変 反変 [ +T ] [ -T ] <__covariant T> <__contravariant T> Array<T> が対応 T -> S の引数型 Tが対応
  • 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