Publicidad
Publicidad

Más contenido relacionado

Presentaciones para ti(20)

Publicidad

Más de Tomohiro Kumagai(20)

Último(20)

Publicidad

Swift 2.0 大域関数の行方から #swift2symposium

  1. EZ-‐‑‒NET  熊⾕谷友宏   http://ez-‐‑‒net.jp/ Swift 2.0 2015.06.28   @  Swift  2  (&  LLDB)  シンポジウム ⼤大域関数の⾏行行⽅方から
  2. 熊谷友宏 EZ-NET http://ez-net.jp/ @es_kumagai Xcode 5 徹底解説 IP Phone 音でダイヤル 音で再配達ゴッド いつもの電卓 with 割勘ウォッチ MOSA
  3. Swift 2.0 で 衝撃的だった出来事
  4. 大域関数の大胆な削減
  5. • abs • advance • alignof • alignofValue • assert • assertionFailure • contains • count • debugPrint • debugPrintln • distance • dropFirst • dropLast • dump • enumerate • equal • extend • fatalError • filter • find • first • flatMap • getVaList • indices • insert • isEmpty • isUniquelyRefer enced • isUniquelyRefer encedNonObjC • join • last • lazy • lexicographicalC ompare • map • max • maxElement • min • minElement • numericCast • overlaps • partition • precondition • preconditionFail ure • prefix • print • println • reduce • reflect • removeAll • removeAtIndex • removeLast • removeRange • reverse • sizeof • sizeofValue • sort • sorted • splice • split • startsWith • stride • strideof • strideofValue • suffix • swap • toDebugString • toString • transcode • underestimateC ount • unsafeAddress Of • unsafeBitCast • unsafeDowncast • unsafeUnwrap • withExtendedLif etime • withUnsafeMuta blePointer • withUnsafeMuta blePointers • withUnsafePoint er • withUnsafePoint ers • withVaList • zip Swift 1.2
  6. • abs • advance • alignof • alignofValue • assert • assertionFailure • contains • count • debugPrint • debugPrintln • distance • dropFirst • dropLast • dump • enumerate • equal • extend • fatalError • filter • find • first • flatMap • getVaList • indices • insert • isEmpty • isUniquelyRefer enced • isUniquelyRefer encedNonObjC • join • last • lazy • lexicographicalC ompare • map • max • maxElement • min • minElement • numericCast • overlaps • partition • precondition • preconditionFail ure • prefix • print • println • reduce • reflect • removeAll • removeAtIndex • removeLast • removeRange • reverse • sizeof • sizeofValue • sort • sorted • splice • split • startsWith • stride • strideof • strideofValue • suffix • swap • toDebugString • toString • transcode • underestimateC ount • unsafeAddress Of • unsafeBitCast • unsafeDowncast • unsafeUnwrap • withExtendedLif etime • withUnsafeMuta blePointer • withUnsafeMuta blePointers • withUnsafePoint er • withUnsafePoint ers • withVaList • zip • anyGenerator • readLine Swift 2.0
  7. ################################################################################# 思ったほどは消えてない? ++ -------------------------
  8. なぜ大胆に削除されたと感じたか
  9. • contains • count • debugPrintln • enumerate • equal • filter • find • first • flatMap • indices • isEmpty • last • lexicographicalCompare • map • maxElement • minElement • partition • println • reduce • reverse • sorted • startsWith • toDebugString • toString • underestimateCount 削除された大域関数 Swift 2.0
  10. 削除された大域関数のすべてが ジェネリック関数
  11. おさらい
  12. プロトコル 型の振る舞いを決めるもの
  13. ジェネリック 型に縛られないプログラミング
  14. protocol CollectionType { typealias Element typealias Index : ForwardIndexType subscript(index:Index) -> Element { get } var startIndex:Index { get } var endIndex:Index { get } } プロトコル プロトコルを定義する これらの機能が使えることを保証 Swift 1.2
  15. func count<T:CollectionType>(collection:T) -> T.Index.Distance { let start = collection.startIndex let end = collection.endIndex return distance(start, end) } ジェネリック関数 プロトコルを想定して機能をつくる 保証された機能を使ってプログラミング Swift 1.2
  16. 機能ができたら型をつくる
  17. struct Month { var days:Array<Day> init(days:Int) { self.days = (1...days).map(Day.init) } } 型をつくる データ構造を決める Swift 1.2
  18. extension Month : CollectionType { subscript(index:Int) -> Day { return self.days[index - 1] } var startIndex:Int { return 1 } var endIndex:Int { return self.days.count + 1 } } 型をつくる プロトコルに基づき振る舞いを決める Swift 1.2
  19. 機能を使う
  20. 機能を使う ジェネリック関数を使う let june = Month(days: 30) // 数えられるようになっている count(june) Swift 1.2
  21. struct Year : CollectionType { : : } 機能を使う 新しく型を作ったときも使える let year = Year(2015) // 同じ関数をすぐに使える count(year) Swift 1.2
  22. ジェネリックプログラミング 振る舞いに着目して組み上げるのが
  23. ジェネリックプログラミング 得られる恩恵 ▶ 型を作るときに構造に専念できる ▶ 型に備えるべき機能がプロトコルで判る ▶ 機能を共用化できる ▶ 未知の型にも対応できる ▶ 準拠するプロトコルから出来ることが判る
  24. 大域関数の削除
  25. 大域関数の削除が気になったのか プロトコルを活かす仕組みだったから そもそもなぜ
  26. protocol CollectionType { } プロトコルと機能の実装 プロトコルを定義して それを使った型を作る struct Array<T> : CollectionType { 
 } struct Dictionary<Key,Value> : CollectionType {
 } Swift 1.2
  27. 大域にジェネリック関数を えると func count<T:CollectionType>(x:T)
 -> T.Index.Distance func indices<C:CollectionType>(x:C)
 -> Range<C.Index> let array = Array<Int>() let dictionary = Dictionary<String,Int>() count(array) count(dictionary) プロトコルと機能の実装 どちらの型にでも使える Swift 1.2
  28. 気になっていたこと Swift 1.2 で
  29. struct Array<T> : CollectionType { var count: Int { get } } 両方に同じ機能がある 型にも実装されていたり Swift 1.2 大域関数に実装されているものが func count<T:CollectionType>(x:T)
 -> T.Index.Distance
  30. なぜ両方にあるのか ▶ 大域関数にある機能をなぜ型にも? ▶ array.count と書く方が便利だから? let c = count(array) let c = array.count どちらも同じ機能 Swift 1.2
  31. 大域関数だけで良いのでは…? Swift 1.2
  32. むしろ大域関数が消滅 Swift 2.0
  33. 大域関数の行方
  34. 削除だけでは済まないはず それぞれの型に固有な実装へ 汎用的な大域関数が Swift 2.0
  35. SequenceType • contains • enumerate • filter • flatMap • lexicographicalCompare • map • maxElement • minElement • reduce • reverse • sorted • startsWith • underestimateCount MutableCollectionType • partition CollectionType • count • first • filter • isEmpty • last • indexOf (find) • indices String • init: (toString) • init:reflecting: (toDebugString) 削除 • debugPrintln • println 大域関数の行方 Swift 2.0
  36. 移動先の多くが Protocol Extension
  37. Protocol Extension ▶ プロトコルを拡張する機能 ▶ 既定の実装を記載できる ▶ プロトコルに規定された機能で実装する ▶ 型エイリアスの種類で実装を変えられる Swift 2.0 特徴
  38. protocol CollectionType { typealias Element typealias Index : ForwardIndexType subscript(index:Index) -> Element { get } var startIndex:Index { get } var endIndex:Index { get } } Protocol Extension Swift 2.0 たとえば、こんなプロトコルがあったとき
  39. extension CollectionType { var count:Index.Distance { return distance(self.startIndex, self.endIndex) } var indices:Range<Index> { return self.startIndex ..< self.endIndex } } Protocol Extension Swift 2.0 プロトコル拡張で振る舞いから機能を実装
  40. struct Month : CollectionType { subscript(index:Int) -> Day { return self.days[index - 1] } var startIndex:Int { return 1 } var endIndex:Int { return self.days.count + 1 } } Protocol Extension Swift 2.0 型では最低限の機能だけを実装すれば
  41. let month = Month() month.count month.indices Protocol Extension Swift 2.0 プロトコル拡張で実装した機能も使える
  42. つまり
  43. protocol CollectionType { typealias Element typealias Index : ForwardIndexType subscript(index:Index) -> Element { get } var startIndex:Index { get } var endIndex:Index { get } } Swift 1.2 // 機能は大域関数で提供 func count<T:CollectionType>(x:T) -> T.Index.Distance { return distance(x.startIndex, x.endIndex) } func indices<C:CollectionType>(x:C) -> Range<C.Index> { return x.startIndex ..< x.endIndex } // 振る舞いをプロトコルで規定
  44. protocol CollectionType { typealias Element typealias Index : ForwardIndexType subscript(index:Index) -> Element { get } var startIndex:Index { get } var endIndex:Index { get } } extension CollectionType { var count:Index.Distance { return distance(self.startIndex, self.endIndex) } var indices:Range<Index> { return self.startIndex ..< self.endIndex } } // 振る舞いも機能もプロトコル内に集約 Swift 2.0
  45. 嬉しいポイント Protocol Extension
  46. let array = Array<String>() array.count 1. コード補完が効く Protocol Extension ▶ 所属する機能として候補に挙がる ▶ 思考の流れどおりに書ける
  47. extension CollectionType
 where Element : IntegerType { var total:Element { return self.reduce(0, combine:+) } } 2. 条件付きで拡張できる Protocol Extension ▶ 型エイリアスで条件を指定できる ▶ 条件を満たす型にだけ機能が追加される
  48. let intArray = Array<Int>() let strArray = Array<String>() intArray.total strArray.total 2. 条件付きで拡張できる Protocol Extension ▶ 条件を満たす型でだけ使える ▶ それ以外の型にはそもそも存在しない
  49. プロトコルを活かせる理想形 Protocol Extension は
  50. Protocol Extension に 想いを馳せる日々
  51. 役割について
  52. ジェネリック関数を置き換える機能? Protocol Extension 〓
  53. Protocol Extension おさらい ▶ ジェネリック関数と同等のことができる ▶ 機能がプロトコルでグループ化される ▶ 補完機能が働くのが嬉しい 大域関数が要らなくなる?
  54. Protocol Extension ジェネリック関数にしかできないこと ▶ 名前空間による完全な衝突回避 衝突の可能性 ▶ プロトコル自体は名前空間で回避できる ▶ 要求する機能が衝突すると回避できない
  55. 衝突について
  56. 1. プロトコル名の衝突 複数のモジュールで同じ名前なら回避可能 // JSON Module protocol ValueType { } // XML Module protocol ValueType { } // モジュールを明記することで回避可能 struct JSONValue : JSON.ValueType { }
  57. 2. 機能の衝突 異なる目的を同じ定義が求めたときは衝突 protocol PNGType { var data:NSData{get} } protocol JPEGType { var data:NSData{get} } struct Picture : PNGType, JPEGType { // どちらの data を期待している? var data:NSData { } } プロトコル名での区別ができない
  58. 2. 機能の衝突 機能名を具体的なものにして衝突を回避する方法 protocol PNGType { var pngData:NSData {get} } protocol JPEGType { var jpegData:NSData {get} } struct Picture : PNGType, JPEGType { // もし名前が衝突しても同じ目的の可能性が高い var jpegData:NSData { } } 名前が長くなりすぎないようには心掛けたい
  59. 2. 機能の衝突 オーバーロードで衝突を回避する方法 protocol PNGType { var data:PNGData {get} } protocol JPEGType { var data:JPEGData {get} } struct Picture : PNGType, JPEGType { // 戻り値が違えば別物として存在できる var data:PNGData { return … } var data:JPEGData { return … } } 独自の型を使えばほぼ衝突は回避できる
  60. struct Picture : ProtoA, ProtoB { 3. 型エイリアスの衝突 同名の型エイリアスが異なる型を期待すると衝突 protocol ProtoA { typealias Element : protocol ProtoB { typealias Element : でも具体例が思いつかない…!
  61. 衝突は案外、心配なさそう
  62. 積極的に活用して行くのが良さそう Protocol Extension は
  63. そもそもの extension について
  64. カテゴリ拡張は避けられていた感 Objective-C の頃は クラスに後から独自のメソッドを追加する機能 【カテゴリ拡張】
  65. 不安を感じない気がする Swift だと extension を使うことに ▶ Objective-C はクラス継承が主体で
 影響範囲が広すぎたから…? ▶ プロトコルの継承が主体で
 拡張するにも動機が明確だから…?
  66. extension の使いどころについて
  67. Protocol Extension 使いどころの判断基準 ▶ 大域関数の代わりとして積極的に活用? ▶ 演算子の実装を除くすべて? ▶ 既存のプロトコルも積極的に拡張? 普通の書き方として使っていくべき?
  68. Any や AnyObject は拡張できない 任意の型やオブジェクトに対する 機能の実装には大域関数が必要 Protocol Extension 拡張できないプロトコルも存在する ( Non-nominal type cannot be extended )
  69. Protocol Extension Swift 2.0 の標準機能は大域関数も存在する ▶ なぜ大域関数として残されているのか ▶ Protocol Extension だけでは問題なのか? func abs<T:SignedNumberType>(x:T) -> T func advance<T:ForwardIndexType> (start:T, _ n:T.Distance) -> T なにか理由があるのだろうか
  70. Protocol Extension 存在理由が分かる気がする大域関数 ▶ stride は気持ちが分かる気がする ▶ Strideable を操作するのではなく
 値を使って Stride 型を得ることが目的 ▶ 実際 Protocol Extension されていない func stride<T:Strideable>(from start:T, through end:T, by stride:T.Stride) -> StrideThrough<T>
  71. Protocol Extension 存在理由がよくわからない大域関数 ▶ Protocol Extension だけで十分そう ▶ 深い事情で残されているわけではない? ▶ それとも inout が何か を握っている? func removeAll <C:RangeReplaceableCollectionType> (inout x:C, keepCapacity:Bool = default)
  72. まとめ
  73. Swift 2.0 大域関数の行方から ▶ 大域関数の大胆な削減 ✴ 大域関数は Protocol Extension へ ▶ Protocol Extension の気になるところ ✴ 名前の衝突は心配要らなそう? ✴ 既存プロトコルも積極的に拡張できそう? ▶ Protocol Extension の使いどころ ✴ 大域関数を置き換える機能? ✴ 大域関数は標準ライブラリに残っている ✴ 使い分けのポイントがあるのだろうか
Publicidad