Slide 1

Slide 1 text

Protocol Extension ishkawa 1 / 34

Slide 2

Slide 2 text

2 / 34

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Swift 1 の protocol 4 / 34

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Swift 2 の protocol 10 / 34

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Swift 1 の map 16 / 34

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

型制約つき protocol extension 22 / 34

Slide 23

Slide 23 text

型制約つきグローバル関数 特定の条件を満たす型だけに実行できる関数もある 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

Slide 24

Slide 24 text

型制約つき 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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

抽象クラスの継承の問題 何を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

Slide 28

Slide 28 text

抽象クラスの継承の問題 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

Slide 29

Slide 29 text

抽象化による型の損失 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

Slide 30

Slide 30 text

抽象化による型の損失 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

Slide 31

Slide 31 text

抽象的かつ型安全なコードの他の例 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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

34 / 34