Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Protocol Extension

Protocol Extension

Yosuke Ishikawa

June 28, 2015
Tweet

More Decks by Yosuke Ishikawa

Other Decks in Programming

Transcript

  1. Protocol Extension
    ishkawa
    1 / 34

    View Slide

  2. 2 / 34

    View Slide

  3. Protocol Extension
    p
    r
    o
    t
    o
    c
    o
    l M
    y
    P
    r
    o
    t
    o
    c
    o
    l {
    v
    a
    r n
    a
    m
    e
    : S
    t
    r
    i
    n
    g { g
    e
    t }
    f
    u
    n
    c d
    o
    S
    o
    m
    e
    t
    h
    i
    n
    g
    (
    )
    }
    e
    x
    t
    e
    n
    s
    i
    o
    n M
    y
    P
    r
    o
    t
    o
    c
    o
    l {
    v
    a
    r n
    a
    m
    e
    : S
    t
    r
    i
    n
    g {
    r
    e
    t
    u
    r
    n "
    i
    s
    h
    k
    a
    w
    a
    "
    }
    f
    u
    n
    c d
    o
    S
    o
    m
    e
    t
    h
    i
    n
    g
    (
    ) {
    }
    }
    3 / 34

    View Slide

  4. Swift 1

    protocol
    4 / 34

    View Slide

  5. Swift 1

    protocol
    インター
    フェー
    スを定義
    p
    r
    o
    t
    o
    c
    o
    l D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    ) -
    > I
    n
    t
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t
    }
    5 / 34

    View Slide

  6. Swift 1

    protocol
    適合する型で実装
    c
    l
    a
    s
    s V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    : U
    I
    V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    , D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    ) -
    > I
    n
    t {
    r
    e
    t
    u
    r
    n 1
    }
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t {
    r
    e
    t
    u
    r
    n 1
    }
    }
    6 / 34

    View Slide

  7. Swift 1

    protocol
    @
    o
    b
    j
    c
    ならo
    p
    t
    i
    o
    n
    a
    l
    を定義できる
    @
    o
    b
    j
    c p
    r
    o
    t
    o
    c
    o
    l D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    o
    p
    t
    i
    o
    n
    a
    l f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    ) -
    > I
    n
    t
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t
    }
    7 / 34

    View Slide

  8. Swift 1

    protocol
    o
    p
    t
    i
    o
    n
    a
    l
    は実装しなくても良い
    c
    l
    a
    s
    s V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    : U
    I
    V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    , D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t {
    r
    e
    t
    u
    r
    n 1
    }
    }
    8 / 34

    View Slide

  9. Swift 1

    protocol
    n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    )
    の実装の有無は呼び出し側でハンドル
    デフォルトの動作は利用側が用意する
    l
    e
    t d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    : D
    a
    t
    a
    S
    o
    u
    r
    c
    e
    l
    e
    t n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s = d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    .
    n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    ?
    (
    ) ?
    ? 1
    9 / 34

    View Slide

  10. Swift 2

    protocol
    10 / 34

    View Slide

  11. Swift 2

    protocol
    インター
    フェー
    スを定義
    p
    r
    o
    t
    o
    c
    o
    l D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    ) -
    > I
    n
    t
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t
    }
    e
    x
    t
    e
    n
    s
    i
    o
    n
    でデフォルトの実装を定義
    p
    r
    o
    t
    o
    c
    o
    l D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    ) -
    > I
    n
    t {
    r
    e
    t
    u
    r
    n 1
    }
    }
    11 / 34

    View Slide

  12. Swift 2

    protocol
    protocol extension
    で実装されているものは実装しなくても良い
    c
    l
    a
    s
    s V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    : U
    I
    V
    i
    e
    w
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    , D
    a
    t
    a
    S
    o
    u
    r
    c
    e {
    f
    u
    n
    c n
    u
    m
    b
    e
    r
    O
    f
    I
    t
    e
    m
    s
    I
    n
    S
    e
    c
    t
    i
    o
    n
    (
    s
    e
    c
    t
    i
    o
    n
    : I
    n
    t
    ) -
    > I
    n
    t {
    r
    e
    t
    u
    r
    n 1
    }
    }
    12 / 34

    View Slide

  13. Swift 2

    protocol
    デフォルトの動作はprotocol extension
    が用意している
    利用側は適合している型が実装しているか気にする必要はない
    l
    e
    t d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    : D
    a
    t
    a
    S
    o
    u
    r
    c
    e
    l
    e
    t n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s = d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    .
    n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    (
    )
    13 / 34

    View Slide

  14. Swift 2

    protocol
    protocol
    にデフォルト実装を定義できるようになった
    デフォルト実装による設計の変化
    @
    o
    b
    j
    c
    にしなくてもo
    p
    t
    i
    o
    n
    a
    l
    (
    のようなもの)
    を提供できる
    デフォルトの動作の定義を利用側からprotocol
    側に移せる
    /
    / o
    p
    t
    i
    o
    n
    a
    l
    の場合(
    S
    w
    i
    f
    t 1
    , 2
    )
    l
    e
    t n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s = d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    .
    n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    ?
    (
    ) ?
    ? 1
    /
    / p
    r
    o
    t
    o
    c
    o
    l e
    x
    t
    e
    n
    s
    i
    o
    n
    の場合(
    S
    w
    i
    f
    t 2
    )
    l
    e
    t n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s = d
    a
    t
    a
    S
    o
    u
    r
    c
    e
    .
    n
    u
    m
    b
    e
    r
    O
    f
    S
    e
    c
    t
    i
    o
    n
    s
    14 / 34

    View Slide

  15. Swift
    標準ライブラリの変化
    15 / 34

    View Slide

  16. Swift 1

    map
    16 / 34

    View Slide

  17. Swift 1

    map
    定義
    f
    u
    n
    c m
    a
    p
    <
    C
    : C
    o
    l
    l
    e
    c
    t
    i
    o
    n
    T
    y
    p
    e
    , T
    >
    (
    s
    o
    u
    r
    c
    e
    : C
    , t
    r
    a
    n
    s
    f
    o
    r
    m
    : (
    C
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t
    ) -
    > T
    ) -
    > [
    T
    ]
    利用例
    l
    e
    t n
    a
    m
    e
    s = [
    "
    f
    o
    o
    "
    , "
    b
    a
    r
    "
    , "
    b
    a
    z
    "
    ]
    l
    e
    t c
    o
    u
    n
    t
    s = m
    a
    p
    (
    n
    a
    m
    e
    s
    ) { n
    a
    m
    e i
    n
    c
    o
    u
    n
    t
    (
    n
    a
    m
    e
    )
    }
    汎用的だがグロー
    バル関数はコー
    ド補完から探すのが面倒
    17 / 34

    View Slide

  18. Swift 1

    map
    型ごとにメソッドとしても定義されている
    e
    x
    t
    e
    n
    s
    i
    o
    n A
    r
    r
    a
    y {
    f
    u
    n
    c m
    a
    p
    <
    U
    >
    (
    t
    r
    a
    n
    s
    f
    o
    r
    m
    : (
    T
    ) -
    > U
    ) -
    > [
    U
    ]
    }
    利用例
    l
    e
    t n
    a
    m
    e
    s = [
    "
    f
    o
    o
    "
    , "
    b
    a
    r
    "
    , "
    b
    a
    z
    "
    ]
    l
    e
    t c
    o
    u
    n
    t
    s = n
    a
    m
    e
    s
    .
    m
    a
    p { n
    a
    m
    e i
    n
    c
    o
    u
    n
    t
    (
    n
    a
    m
    e
    )
    }
    型ごとに定義...
    18 / 34

    View Slide

  19. Swift 2

    map
    グローバル関数
    → protocol extension
    19 / 34

    View Slide

  20. Swift 2

    map
    定義
    e
    x
    t
    e
    n
    s
    i
    o
    n C
    o
    l
    l
    e
    c
    t
    i
    o
    n
    T
    y
    p
    e {
    f
    u
    n
    c m
    a
    p
    <
    T
    >
    (
    @
    n
    o
    e
    s
    c
    a
    p
    e t
    r
    a
    n
    s
    f
    o
    r
    m
    : (
    S
    e
    l
    f
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t
    ) -
    > T
    ) -
    > [
    T
    ]
    }
    利用例
    l
    e
    t c
    o
    u
    n
    t
    s
    : [
    I
    n
    t
    ] = n
    a
    m
    e
    s
    .
    m
    a
    p { n
    a
    m
    e i
    n
    n
    a
    m
    e
    .
    c
    h
    a
    r
    a
    c
    t
    e
    r
    s
    .
    c
    o
    u
    n
    t
    }
    型ごとに定義しなくてもメソッドとして利用できる
    20 / 34

    View Slide

  21. map
    はどう変わったか
    達成したい条件
    C
    o
    l
    l
    e
    c
    t
    i
    o
    n
    T
    y
    p
    e
    に対して適用できるようにしたい
    メソッドとして提供したい
    Swift 1
    グロー
    バル関数でC
    o
    l
    l
    e
    c
    t
    i
    o
    n
    T
    y
    p
    e
    への適用を提供
    A
    r
    r
    a
    y
    など型ごとにメソッドを提供
    Swift 2
    C
    o
    l
    l
    e
    c
    t
    i
    o
    n
    T
    y
    p
    e
    のprotocol extension
    でメソッドを提供
    21 / 34

    View Slide

  22. 型制約つき
    protocol extension
    22 / 34

    View Slide

  23. 型制約つきグローバル関数
    特定の条件を満たす型だけに実行できる関数もある
    SequenceType
    に適合している型C
    のうち、
    要素となる
    C.Generator.Element
    がComparable
    に適合していればs
    o
    r
    t
    e
    d
    (
    )

    実行できる。
    /
    / S
    w
    i
    f
    t 1
    f
    u
    n
    c s
    o
    r
    t
    e
    d
    <
    C
    : S
    e
    q
    u
    e
    n
    c
    e
    T
    y
    p
    e w
    h
    e
    r
    e C
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t
    : C
    o
    m
    p
    a
    r
    a
    b
    l
    e
    >
    (
    s
    o
    u
    r
    c
    e
    : C
    ) -
    > [
    C
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t
    ]
    23 / 34

    View Slide

  24. 型制約つき
    protocol extension
    条件を満たす型のみprotocol extension
    を定義することもできる
    e
    x
    t
    e
    n
    s
    i
    o
    n S
    e
    q
    u
    e
    n
    c
    e
    T
    y
    p
    e w
    h
    e
    r
    e S
    e
    l
    f
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t : C
    o
    m
    p
    a
    r
    a
    b
    l
    e {
    f
    u
    n
    c s
    o
    r
    t
    (
    ) -
    > [
    S
    e
    l
    f
    .
    G
    e
    n
    e
    r
    a
    t
    o
    r
    .
    E
    l
    e
    m
    e
    n
    t
    ]
    }
    24 / 34

    View Slide

  25. Protocol Oriented
    Programming
    WWDC 2015
    の"Protocol Oriented Programming in Swift"
    というトー
    クから理解したことをまとめます。
    25 / 34

    View Slide

  26. 3
    行で
    class
    にはいくつか問題がある
    protocol + struct
    で解決できる
    なるべくprotocol + struct
    を使おう
    26 / 34

    View Slide

  27. 抽象クラスの継承の問題
    何をoverride
    すればいいのかわからない
    ドキュメント以外から知ることは難しい
    /
    /
    抽象クラス
    c
    l
    a
    s
    s O
    r
    d
    e
    r
    e
    d {
    f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : O
    r
    d
    e
    r
    e
    d
    ) -
    > B
    o
    o
    l {
    f
    a
    t
    a
    l
    E
    r
    r
    o
    r
    (
    "
    i
    m
    p
    l
    e
    m
    e
    n
    t m
    e
    !
    "
    )
    }
    }
    override
    が必要なものの抽象クラス側での実装を、f
    a
    t
    a
    l
    E
    r
    r
    o
    r

    しておけばサブクラスでの実装が必要であることを知らせること
    はできる。
    エラー
    はコンパイル時に知りたいがf
    a
    t
    a
    l
    E
    r
    r
    o
    r
    (
    )
    は実行時
    27 / 34

    View Slide

  28. 抽象クラスの継承の問題
    protocol
    では実装すべきものが明らか
    /
    /
    抽象クラスをp
    r
    o
    t
    o
    c
    o
    l
    に置き換え
    p
    r
    o
    t
    o
    c
    o
    l O
    r
    d
    e
    r
    e
    d {
    f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : O
    r
    d
    e
    r
    e
    d
    ) -
    > B
    o
    o
    l
    }
    実装漏れはコンパイル時に知ることができる
    デフォルト実装はprotocol extension
    で定義できる
    28 / 34

    View Slide

  29. 抽象化による型の損失
    c
    l
    a
    s
    s O
    r
    d
    e
    r
    e
    d {
    f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : O
    r
    d
    e
    r
    e
    d
    ) -
    > B
    o
    o
    l {
    f
    a
    t
    a
    l
    E
    r
    r
    o
    r
    (
    )
    }
    }
    c
    l
    a
    s
    s N
    u
    m
    b
    e
    r
    : O
    r
    d
    e
    r
    e
    d {
    o
    v
    e
    r
    r
    i
    d
    e f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : O
    r
    d
    e
    r
    e
    d
    ) -
    > B
    o
    o
    l {
    l
    e
    t o
    t
    h
    e
    r
    N
    u
    m
    b
    e
    r = o
    t
    h
    e
    r a
    s
    ! N
    u
    m
    b
    e
    r
    .
    .
    .
    }
    }
    override
    したメソッドの型は変更できない
    Number
    のprecedes()
    に他のサブクラスが入る可能性もある
    つまり、
    抽象的なコー
    ドを型安全に書けない
    29 / 34

    View Slide

  30. 抽象化による型の損失
    p
    r
    o
    t
    o
    c
    o
    l O
    r
    d
    e
    r
    e
    d {
    f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : S
    e
    l
    f
    ) -
    > B
    o
    o
    l
    }
    s
    t
    r
    u
    c
    t N
    u
    m
    b
    e
    r
    : O
    r
    d
    e
    r
    e
    d {
    f
    u
    n
    c p
    r
    e
    c
    e
    d
    e
    s
    (
    o
    t
    h
    e
    r
    : N
    u
    m
    b
    e
    r
    ) -
    > B
    o
    o
    l {
    .
    .
    .
    }
    }
    protocol
    ではSelf
    が利用できる
    precedes()
    の引数にはNumber
    以外の型は入らない
    30 / 34

    View Slide

  31. 抽象的かつ型安全なコードの他の例
    p
    u
    b
    l
    i
    c p
    r
    o
    t
    o
    c
    o
    l R
    e
    q
    u
    e
    s
    t {
    t
    y
    p
    e
    a
    l
    i
    a
    s R
    e
    s
    p
    o
    n
    s
    e
    f
    u
    n
    c e
    x
    e
    c
    u
    t
    e
    (
    R
    e
    s
    p
    o
    n
    s
    e -
    > V
    o
    i
    d
    )
    }
    s
    t
    r
    u
    c
    t G
    e
    t
    R
    e
    p
    o
    s
    i
    t
    o
    r
    y
    R
    e
    q
    u
    e
    s
    t
    : R
    e
    q
    u
    e
    s
    t {
    t
    y
    p
    e
    a
    l
    i
    a
    s R
    e
    s
    p
    o
    n
    s
    e = R
    e
    p
    o
    s
    i
    t
    o
    r
    y
    }
    s
    t
    r
    u
    c
    t G
    e
    t
    U
    s
    e
    r
    R
    e
    q
    u
    e
    s
    t
    : R
    e
    q
    u
    e
    s
    t {
    t
    y
    p
    e
    a
    l
    i
    a
    s R
    e
    s
    p
    o
    n
    s
    e = U
    s
    e
    r
    }
    l
    e
    t r
    e
    p
    o
    s
    i
    t
    o
    r
    y
    R
    e
    q
    u
    e
    s
    t = G
    e
    t
    R
    e
    p
    o
    s
    i
    t
    o
    r
    y
    R
    e
    q
    u
    e
    s
    t
    (
    )
    r
    e
    p
    o
    s
    i
    t
    o
    r
    y
    R
    e
    q
    u
    e
    s
    t
    .
    e
    x
    e
    c
    u
    t
    e { r
    e
    s
    p
    o
    n
    s
    e i
    n
    /
    / r
    e
    s
    p
    o
    n
    s
    e
    はR
    e
    p
    o
    s
    i
    t
    o
    r
    y
    }
    l
    e
    t u
    s
    e
    r
    R
    e
    q
    u
    e
    s
    t = G
    e
    t
    U
    s
    e
    r
    R
    e
    q
    u
    e
    s
    t
    (
    )
    u
    s
    e
    r
    R
    e
    q
    u
    e
    s
    t
    .
    e
    x
    e
    c
    u
    t
    e { r
    e
    s
    p
    o
    n
    s
    e i
    n
    /
    / r
    e
    s
    p
    o
    n
    s
    e
    はU
    s
    e
    r
    }
    31 / 34

    View Slide

  32. どちらを採用するべきか
    どちらもインター
    フェー
    スと実装の両方を提供し、
    継承が可能と
    いう点では似ているが、
    抽象的なコー
    ドにはプロトコルの方が向
    いている。
    抽象クラスは実装の要求が不明確
    抽象クラスでは抽象的なコー
    ドを型安全に書けない
    とはいえ、
    プロトコルに弱点がないわけでもない
    デフォルト実装(
    クラスのsuper
    相当)
    への参照ができない
    stored property
    を持つことができない
    32 / 34

    View Slide

  33. まとめ
    プロトコルにデフォルト実装が定義できるようになった
    標準ライブラリもそれを活かしたつくりに変わってきている
    抽象クラスをプロトコルで置き換えるという流れがある
    33 / 34

    View Slide

  34. 34 / 34

    View Slide