はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech

>100 Views

September 16, 16

スライド概要

iOSDC でも話題に登った Phantom Type という存在が気になって、その得体知れないものを知るために、闇雲に特徴を探ってみたお話です。

※ Docswell での公開に移行する直前の Slideshare での閲覧数は 2,945 でした。

profile-image

正統派趣味人プログラマー。プログラミングとは幼馴染です。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

͸͡Ίͯ1IBOUPNͱૺ۰ͯ͠ ҋӢʹಆ͍Λ௅ΜͰΈͨ࿩ Վ෣‫࠲ب‬UFDI 4XJGUϓϩάϥϛϯάษ‫ڧ‬ձPO &;/&5‫۽‬୩༑޺ IUUQF[OFUKQ 4XJGU

2.

‫۽‬୩༑޺ 5PNPIJSP,VNBHBJ ⾣ 4XJGU‫͕ޠݴ‬௒େ޷͖Ͱ͢ʂ ⾣ ΈΜͳͰָ͠Ήษ‫ڧ‬ձ͕େ޷͖Ͱ͢ʂ ⾣ ϓϩάϥϛϯάͷָ͠͞Λ఻͍͖͍͑ͯͨɻ !FT@LVNBHBJ UPNPIJSPLVNBHBJ $PEF1JFDFGPSNBD04 IUUQF[OFUKQ 9DPEFపఈղઆ

3.

$PEF1JFDFGPSNBD04 ษ‫ڧ‬ձΛָ͠ΉΞϓϦ ⾣ ιʔείʔυΛ5XJUUFSͱ(JTUʹಉ࣌౤ߘ ⾣ ίʔυཝΛۭʹ͢Ε͹ɺී௨ʹπΠʔτՄೳ ⾣ ϋογϡλάΛઃఆͰ͖Δʗ෇͚๨Εͳ͍ #kbkz_tech

4.

ษ‫ڧ‬ձΛ։࠵͍ͯ͠·͢ɻ Θ͍Θ͍ɺָ͘͠ɺ ΈΜͳͰ‫ޠ‬Β͑Δ৔ॴΛ໨ࢦͯ͠ ԣ඿J1IPOF։ൃऀษ‫ڧ‬ձ ୈճ໨͸݄೔ͷ։࠵ʢ໨ඪʣ ZJEFW ˏԣ඿ɾഅंಓ IUUQTBUOEPSHHSPVQTZJEFW ΧδϡΞϧ4XJGUษ‫ڧ‬ձ ΈΜͳͰ4XJGU ෮शձ DTXJGU !ԣ඿ɾ੨༿୆ NJOOB@EF@TXJGU ˏौ୩ ୈճ໨Λ݄೔ʹ։࠵ ୈճ໨Λ݄೔ʹ։࠵ IUUQTBUOEPSHHSPVQTDTXJGU IUUQDTXJGUDPOOQBTTDPN

5.

ωοτϥδΦ Ќ์ૹ։࢝ɻ ϓϩάϥϛϯά͕େ޷͖ͳ̎ਓͰɺ ϓϩάϥϜ‫ޠָ͍ͯͭ͘͠ʹޠݴ‬Β͏൪૊ NPPLNPPLSBEJP Ќ൛ ϜοΫϜοΫϥδΦ ‫۽‬୩ͱ៸໘͕ϓϩάϥϛϯάίʔυͷ಺͔Β ௌ͑ͯ͘͜Δ੠ʹࣖΛ܏ָ͚ͯ͠ΉϥδΦ ୈ࿩ʜ݄೔ΑΓ์ૹ։࢝ୈ࿩ʜ݄೔ͷ์ૹ༧ఆ IUUQNPPLNPPLSBEJPDPNB

6.

͸͡Ίͯ1IBOUPNͱૺ۰ͯ͠ ҋӢʹಆ͍Λ௅ΜͰΈͨ࿩ Πϥετग़లIUUQ‫ق‬અͷΠϕϯτDPN

7.

ɾɾɾ

8.

Ͱ៸໘͞Μ͕ັͤͯ͘Εͨ 1IBOUPN5ZQF IUUQTXXXZPVUVCFDPNXBUDI WORG)M+--D

9.

ͨͱ͑͹ɻ QSFQBSF͸̍౓͖Γʹ͍ͯͩ͘͠͞ʂ ⾣ ࣮ߦ੍‫ޚ‬͸ɺϥϯλΠϜͰߦ͏ͷ͕ৗࣝɻ ⾣ ઃ‫ऀܭ‬͸ϥϯλΠϜͰͦͷҙਤΛ͍ࣔͯͨ͠ɻ class HogeOperation { private(set) var isPrepared = false func prepare() { guard !isPrepared else { fatalError("prepare を複数回呼ばないこと") } isPrepared = true } }

10.

៸໘͞Μ͕‫ͯͤ͘ݟ‬Εͨ 1IBOUPN5ZQFͱ͍͏ղ๏ ⾣ ‫ͦܕ‬ͷ΋ͷʹঢ়ଶΛ౰ͯࠐΈɺίʔυΛ੍‫͢ޚ‬Δ ⾣ ઃ‫ऀܭ‬ͷҙਤ͕ίʔσΟϯά࣌ʹϓϩάϥϚʔʹ఻ΘΔ // Init 状態の HogeOperation を生成 let operation = HogeOperation<Init>() // 最初は prepared を呼べて準備完了したものを取得可能 let preparedOp = operation.prepared() // 準備が終われば prepared はビルドエラーで実行不可 preparedOp.prepared() b1SFQBSFE`JTOPUBTVCUZQFPGb*OJU`

11.

1IBOUPN5ZQFͷ࡞Γํ

12.

1IBOUPN5ZQFͷ࡞Γํ ঢ়ଶΛઃ‫͢ܭ‬Δ ⾣ ঢ়ଶ͝ͱʹΫϥεΛఆٛ͢Δ ⾣ ϓϩτίϧΛఴ͑Ε͹ɺऔΓಘΔঢ়ଶ͕໌֬ʹͳΔ // これで "操作状態を表現する型" を表現 protocol OperationState {} // 操作状態ごとにクラスを定義 class Init: OperationState {} class Prepared: OperationState {}

13.

1IBOUPN5ZQFͷ࡞Γํ ‫ܕ‬Λઃ‫͢ܭ‬Δ ⾣ ‫ܕ‬ύϥϝʔλʔͰঢ়ଶΛ࣋ͨͤΔ ⾣ ঢ়ଶ͸‫ܕ‬Λઆ໌͢Δ͚ͩͰɺ಺෦Ͱ͸࢖Θͳ͍ // 型パラメーターで型に状態を付与 class HogeOperation<State: OperationState> { /* 今回は内部で、 型パラメーターを使わないのがポイント */ }

14.

1IBOUPN5ZQFͷ࡞Γํ ঢ়ଶ͝ͱʹ‫ػ‬ೳΛઃ‫͢ܭ‬Δ ⾣ ੍໿෇͖‫֦ܕ‬ுͰɺঢ়ଶ͝ͱʹ‫ػ‬ೳΛ࣮૷͢Δ ⾣ ྫ͑͹ɺ४උલʹ͸४උ࣮ߦͷ‫ػ‬ೳΛඋ͑Δ extension HogeOperation where State: Init { // 準備を実行し、準備完了状態のインスタンスを返す func prepared() -> HogeOperation<Prepared> {…} } extension HogeOperation where State: Prepared { // 目的の操作を実行する func execute() {…} }

15.

1IBOUPN5ZQF‫׬‬੒

16.

1IBOUPN5ZQF‫׬‬੒ ঢ়ଶʹԠͯ͡ɺ‫ػ‬ೳ͕มΘΔ ⾣ ‫ܕ‬ύϥϝʔλʔΛ‫ػ‬ೳ੾ସ͚ͩʹ࢖͏ͷ͕ϙΠϯτ ⾣ -JWF*TTVFTͷஈ֊ͰίʔσΟϯάϛεʹ‫͚ͮؾ‬Δ let operation = HogeOperation<Init>() // Init 状態では、まだ execute は存在しない operation.execute() b*OJU`JTOPUBTVCUZQFPGb1SFQBSFE` // prepared を呼ぶことで Prepared 状態のものを取得 let preparedOp = operation.prepared() // Prepared 状態には、もう prepared は存在しない preparedOp.prepared() b1SFQBSFE`JTOPUBTVCUZQFPGb*OJU`

17.

ϏϧυλΠϜʹঢ়ଶ൑ఆͱ͔ɺ͍͢͝ʜʂ

18.

͔͠͠ɺ͜ͷಘମͷ஌Εͳ͍ίʔυ͸ʜ 1IBOUPN5ZQFʜԿऀͳΜͩɻ

19.

1IBOUPN5ZQFΛ஌Βͳ͍ࣗ෼͕ ͨͩҋӢʹఁ࡯ͯ͠ɺۭ૝͍ͯ͘͠෺‫ޠ‬ ಆ͏ʹ͸ɺ·ͣɺఢΛ஌Βͳ͚Ε͹ͳΒͳ͍ʜʂ

20.

ࠜຊΛఁ࡯

21.

1IBOUPN5ZQFͬͯͳΜͩΖ͏ʁ

22.

1IBOUPN5ZQFͬͯͳΜͩΖ͏ʁ ‫ܕ‬ύϥϝʔλʔͰɺ‫ܕ‬Λ੍‫͢ޚ‬Δ ⾣ ‫ܕ‬ύϥϝʔλʔ͸Ϗϧυ͕ࡁΜͩΒ໾໨͸ऴΘΓ ⾣ ·ΔͰ༓ྶΈ͍ͨʹফ໓͢Δ͔Β1IBOUPN5ZQFʁ let operation = HogeOperation<Init>() // HogeOperation<Init> 型だから prepared が呼べる let preparedOp: HogeOperation<Prepared>() = operation.prepared() // HogeOperation<Prepared> 型だから execute が呼べる preparedOp.execute() // Init クラスや Prepared クラスを、実行時には使わない // ビルドの段階で、もう役目が済んでいる

23.

༓ྶ‫ܕ‬ʜʁ

24.

༓ྶ‫ܕ‬ʜʁ Ϗϧυ‫ޙ‬͸ɺ༓ྶΈ͍ͨʹফ໓͢Δʁ ⾣ ·Δ‫͑ݟ‬ͷΑ͏͕ͩʜ ⾣ ϥϯλΠϜͰɺϝλλΠϓΛऔಘͰ͖Δ let operation = HogeOperation<Init>() let preparedOp = operation.prepared() let type1 = type(of: operation) )PHF0QFSBUJPO*OJU5ZQF let type2 = type(of: preparedOp) )PHF0QFSBUJPO1SFQBSFE5ZQF type1 == type2 // false

25.

༓ྶ‫ܕ‬ʜʁ ϏϧυͰɺ໾໨Λऴ͑Δͱ͍͏ҙຯ ⾣ ‫ܕ‬ύϥϝʔλʔ͕ɺϏϧυ࣌ͷ‫ػ‬ೳ੾ସ͚ͩΛ୲͏ ⾣ Πϯελϯεม਺Ͱ͸࢖Θͣɺ࣮ߦ࣌͸࣮࣭ແҙຯ // 型パラメーターで型に状態を付与 class HogeOperation<State: OperationState> { /* 内部では、型パラメーターを使っていない 型の在り方を説明するためだけに使っている */ ͨͩɺ࢖͏ଆʹͱͬͯɺ‫ܕ‬ύϥϝʔλʔΛ ಺෦Ͱ࢖ͬͯΔ͔͸ؔ৺ͳ͍͠ɺ֎͔Β‫ͯݟ‬΋఻ΘΒͳ͍

26.

δΣωϦοΫ‫ܕ‬ͷԠ༻ʁ

27.

δΣωϦοΫ‫ܕ‬ͷԠ༻ʁ ‫ܕ‬ύϥϝʔλʔ͕ҧ͑͹ɺҧ͏‫ܕ‬ʁ ⾣ "SSBZ4USJOHͱ"SSBZ*OU͸ɺผͷ‫͋Ͱܕ‬Δ ⾣ 1IBOUPN5ZQFʹग़⁊͏·Ͱ͸৴͍ͯͨ͡ /// Phantom Type に出逢う前の認識 // Array はテンプレート的なもので… struct Array<Element> { } // 型パラメーターによって、異なる型になる let values: Array<Int> = Array<String>() DBOOPUDPOWFSUWBMVFPGUZQF"SSBZ*OU UPTQFDJpFEUZQF"SSBZ4USJOH

28.

δΣωϦοΫ‫͍ͳ͘ྑͯ͘ͳͰܕ‬ʁ ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ

29.

ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ঢ়ଶͷఆٛ͸ඞཁͳ͍ ⾣ 1IBOUPN5ZQFΈ͍ͨͳঢ়ଶఆٛ͸ෆཁ ⾣ ঢ়ଶ͸ɺϙϦϞʔϑΟζϜͰද‫͢ݱ‬Δ // protocol OperationState {} // class Init: OperationState {} // class Prepared: OperationState {}

30.

ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ‫ج‬ఈΫϥεͰɺάϧʔϓΛද‫͢ݱ‬Δ ⾣ ‫ج‬ఈΫϥεʹɺ಺෦σʔλͱ‫ڞ‬௨‫ػ‬ೳΛඋ͑Δ ⾣ ‫ܕ‬ύϥϝʔλʔ͸࣋ͨͳ͍ class Operation { fileprivate var data: OperationData fileprivate init(data: OperationData) { self.data = data } func mob() {} }

31.

ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ಋग़ΫϥεͰɺঢ়ଶΛද‫͢ݱ‬Δ ⾣ ঢ়ଶ͝ͱʹɺಋग़ΫϥεΛ࣮૷͢Δ ⾣ ֤ঢ়ଶͰ‫ݻ‬༗ͷ‫ػ‬ೳ͸ɺಋग़Ϋϥεʹ࣮૷͢Δ class OperationInit: Operation { convenience init() {…} func prepared() -> OperationPrepared {…} } class OperationPrepared: Operation { func execute() {…} }

32.

ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ‫׬‬੒ ⾣ ࣮૷ͷҹ৅͸มΘΔ͕ɺಈ࡞తʹ͸΄΅ಉ͜͡ͱ ⾣ ‫Ͱܕ‬ͷঢ়ଶ۠ผ͕ෆࢥ͕ٞͩɺ࣮૷ख๏͸Ұൠత let operation = OperationInit() let preparedOp = operation.prepared() preparedOp.execute()

33.

δΣωϦοΫ‫͍ͳ͘ྑͯ͘ͳͰܕ‬ʁ ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍

34.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ ͻͱͭ໨ͷঢ়ଶΛɺ͋Δ‫Ͱܕ‬ද‫ݱ‬ ⾣ ಺෦σʔλͱ‫ڞ‬௨‫ػ‬ೳΛඋ͑Δ ⾣ ͜ͷঢ়ଶʹ‫ݶ‬Γɺ࢖͑Δ‫ػ‬ೳΛ࣮૷͢Δ struct OperationInit { fileprivate var data: OperationData fileprivate init(data: OperationData) {…} // 共通機能 func mob() {} // 固有の機能 init() {…} func prepared() -> OperationPrepared {…} }

35.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ ΋͏ͻͱͭͷঢ়ଶΛɺผͷ‫Ͱܕ‬ද‫ݱ‬ ⾣ ͪ͜Βʹ΋ɺ಺෦σʔλͱ‫ڞ‬௨‫ػ‬ೳΛඋ͑Δ ⾣ Ϋϥε‫ܧ‬ঝͱҧͬͯɺ‫ڞ‬௨‫ػ‬ೳΛҾ͖‫͍ͳ͛ܧ‬ struct OperationPrepared { fileprivate var data: OperationData fileprivate init(data: OperationData) {…} // 共通機能 func mob() {} // 固有の機能 func execute() {…} }

36.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ ‫׬‬੒ ⾣ ࢖͍উख͸ɺ͜Ε·ͰͷͱมΘΒͳ͍ ⾣ ‫͕ܕ‬ಠཱ͢ΔͨΊɺఆٛ͸ཧղ͠ʹ͘͘ͳΔҹ৅ let operation = OperationInit() let preparedOp = operation.prepared() preparedOp.execute()

37.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ άϧʔϓੑΛɺϓϩτίϧͰද‫ݱ‬ ⾣ ϓϩτίϧΛ౰ͯΕ͹ɺάϧʔϓੑ͸ද‫͖Ͱݱ‬Δ ⾣ ͨͩ͠࢖༻ऀ͸ɺఆٛΛಡ·ͳ͍ͱ‫͍ͳ͚ͮؾ‬ protocol Operation {} struct OperationInit: Operation { … } struct OperationPrepared: Operation { … }

38.

δΣωϦοΫ‫͍ͳ͘ྑͯ͘ͳͰܕ‬ʁ ωετ‫Ͱܕ‬ද‫ͯ͠ݱ‬ΈΔ

39.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ άϧʔϓੑΛɺωετ‫Ͱܕ‬ද‫ݱ‬ ⾣ ‫ܕ‬ͷωετͰ΋ɺάϧʔϓੑ͸ද‫͖Ͱݱ‬Δ ⾣ ݁‫ہ‬ɺঢ়ଶ͝ͱʹ‫͕ܕ‬ಠཱ͢ΔͳΒ༗Γͳબ୒ struct Operation { struct Init { … } struct Prepared { … } }

40.

ผʹɺ‫ܧ‬ঝ͠ͳͯ͘΋͍͍ ‫׬‬੒ ⾣ 0QFSBUJPO*OJU͕0QFSBUJPO*OJUʹͳ͚ͬͨͩ ⾣ ͜Ε͚ͩͰɺ࢖͏ଆʹάϧʔϓ‫఻͕ײ‬ΘΔ let operation = Operation.Init() let preparedOp = operation.prepared() preparedOp.execute()

41.

δΣωϦοΫ‫͍ͳ͘ྑͯ͘ͳͰܕ‬ʁ ωετ‫ͱܕ‬ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ

42.

ωετ‫ͱܕ‬ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ‫ج‬ఈΫϥεͰɺάϧʔϓΛද‫͢ݱ‬Δ ⾣ ‫ج‬ఈΫϥεʹɺ಺෦σʔλͱ‫ڞ‬௨‫ػ‬ೳΛඋ͑Δ ⾣ ͜ΕΛɺ໨ʹ‫͑ݟ‬Δάϧʔϓͱͯ͠΋࢖͏ class Operation { fileprivate var data: OperationData fileprivate init(data: OperationData) { self.data = data } func mob() {} }

43.

ωετ‫ͱܕ‬ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ άϧʔϓੑΛɺωετ‫Ͱܕ‬ද‫ݱ‬ ⾣ ‫ج‬ఈΫϥεʹɺ֤ঢ়ଶΛωετ‫ͯ͠ͱܕ‬ఆٛ ⾣ ωετ‫ݩ‬ͷΫϥεΛɺωετઌͰ‫ܧ‬ঝ͢Δ extension Operation { class Init: Operation { … } class Prepared: Operation { … } }

44.

ωετ‫ͱܕ‬ϙϦϞʔϑΟζϜͰද‫ͯ͠ݱ‬ΈΔ ‫׬‬੒ ⾣ ωετ‫Ͱܕ‬ɺར༻ऀʹάϧʔϓੑΛࣔͤΔ ⾣ ‫ڞ‬௨‫ػ‬ೳΛ‫ج‬ఈΫϥεʹ࣮૷͠ɺҾ͖‫͛ܧ‬Δ let operation = Operation.Init() let preparedOp = operation.prepared() preparedOp.execute()

45.

ࠓ͋Δ஌ࣝͰߟ͚͑ͨͩͰ͸ 1IBOUPN5ZQF͕௫Ίͯ͜ͳ͍ʜ

46.

1IBOUPN5ZQFΛଊ͑Δʹ͸ ҙࣝվֵ͕ඞཁͦ͏ ͦ͏͠ͳ͚Ε͹1IBOUPN5ZQF͕ͻͱͭͷ‫ͯ͑͘ݟʹܕ‬Εͳ͍

47.

ಛ௃Λఁ࡯

48.

‫ͳʹؾ‬Δͷ͸ɺ‫ܕ‬ͷಉҰੑ 1IBOUPN5ZQFҎ֎͸ɺ࣮֬ʹҧ͏‫Ͱܕ‬ද‫͍ͯ͠ݱ‬Δ

49.

ҙࣝվֵ͕ඞཁͦ͏ ‫֦ܕ‬ு͕ඳ͘ੈք ⾣ ੍໿෇͖‫֦ܕ‬ுͰɺಛఆ৚݅ԼͷৼΔ෣͍͕มΘΔ ⾣ ͜ΕΒ͸ɺ޿ٛతʹಉ͡‫ͱܕ‬ଊ͑ͯ΋ྑ͍ʁ class HogeOperation<State: OperationState> { func mob() {…} } extension HogeOperation where State: Init { func prepared() -> HogeOperation<Prepared> {…} } extension HogeOperation where State: Prepared { func execute() {…} }

50.

ҙࣝվֵ͕ඞཁͦ͏ ಉ͡‫ܾͱͩܕ‬ఆ͚ͮΔཧ༝ʹͳΔʁ ⾣ ͦΜͳதɺ1IBOUPN5ZQFͰͷ‫ڍ‬ಈ͕‫ͨͬͳʹؾ‬ ⾣ ະ࣮૷ͷཧ༝͕lαϒλΠϓͰ͸ͳ͍z͔Βʜʁ let operation = HogeOperation<Init>() operation.execute() *OJUJTOPUBTVCUZQFPG1SFQBSFE ผͰ֦ு͞ΕͨϝιουͷଘࡏΛɺೝ͍ࣝͯ͠Δ༷ࢠ

51.

ҙࣝվֵ͕ඞཁͦ͏ Ϋϥε‫ܧ‬ঝͷ৔߹͸ɺΤϥʔ͕ҟͳΔ ⾣ Ϋϥε‫ܧ‬ঝͰ࣮‫͍ͨͯ͠ݱ‬৔߹ɺ‫׬‬શʹଘࡏ͠ͳ͍ ⾣ ผͷ‫͔ͩܕ‬Β࣮૷͕ͳ͍ɺࣗવͳಈ͖ let operation = OperationInit() operation.execute() WBMVFPGUZQF0QFSBUJPO*OJUIBTOPNFNCFS FYFDVUFPQFSBUJPOFYFDVUF δΣωϦοΫ‫ܕ‬͸ɺ޿ٛʹ͸ಉ͡‫ͱܕ‬Έͳͯ͠ྑͦ͞͏

52.

ಉ͡‫ͱܕ‬Έͳͯ͠ྑͦ͞͏ ͨͩ͠ɺΠϯελϯε͸‫׬‬શʹผ෺

53.

ͨͩ͠ɺΠϯελϯε͸‫׬‬શʹผ෺ ‫ܕ‬ύϥϝʔλʔ͕ҧ͑͹ɺ࣮ମ͸ҟͳΔ ⾣ ҟͳΔ࣮ମΛɺಉ͡ม਺Ͱ͸ѻ͑ͳ͍ ⾣ 1IBOUPN5ZQFͷ৔߹ɺಛʹ͕͜͜ॏཁʹͳΓͦ͏ // 準備前と準備後を、自分自身や同じ変数に書き戻せない var operation = HogeOperation<Init>() operation = operation.prepared() DBOOPUBTTJHOWBMVFPGUZQF)PHF0QFSBUJPO1SFQBSFE UPUZQF)PHF0QFSBUJPO*OJU ‫ܕ‬͸ಉ͡Ͱ΋ɺΠϯελϯεΛಉҰࢹ͢Δͷ͸೉͍͠

54.
[beta]
ͨͩ͠ɺΠϯελϯε͸‫׬‬શʹผ෺

ಉҰࢹ͢Δͱɺ୆ແ͠ʹͳΔ
⾣ ϓϩτίϧͰઆ໌͢Ε͹ɺಉҰࢹ͸Ͱ͖Δ
⾣ ͨͩ͠1IBOUPN5ZQFͷྑ͞͸‫׬‬શʹࣦΘΕΔ

protocol Operation {}
class HogeOperation<State: OperationState>: Operation {
}
var op: Operation
op = HogeOperation<Init>()
op = (op as! HogeOperation<Init>).prepared()
op = (op as! HogeOperation<Prepared>).execute()

55.

ঢ়ଶͱͯ͠อ࣋͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ

56.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ ͨͱ͑͹ɺෳࡶͳॳ‫ظ‬Խ͕ඞཁͳͱ͖ ⾣ ๲େͳ೚ҙͷύϥϝʔλʔ͕͋Δͱ͖ ⾣ ΠχγϟϥΠβʔͰͷॳ‫ظ‬Խ͸ɺҾ਺͕๲େʹͳΔ class Driver { init(channel: Int? = nil, volume: Int? = nil, pan: Int? = nil, format: Format? = nil, route: Route? = nil) { } } // 設定項目に何があるかや、設定順番に気を使う let driver = Driver(volume: 10, format: ulaw, route: .speaker)

57.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ 1IBOUPN5ZQFͰྲྀΕΛ࡞Δʜ ⾣ ॳ‫ظ‬ઃఆͱ४උ‫ྃ׬‬Λঢ়ଶͰද‫ݱ‬ ⾣ ઃఆͱར༻Λ໌֬ʹ෼཭Ͱ͖Δ // 本体のクラスを Phantom Type で定義して… class Driver<State> where State: AudioState { } // 準備が整ったときの機能を実装し… extension Driver where State: Ready { func start() { … } }

58.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ 1IBOUPN5ZQFͰྲྀΕΛ࡞Δʜ ⾣ ॳ‫ظ‬ઃఆͱ४උ‫ྃ׬‬Λঢ়ଶͰද‫ݱ‬ ⾣ ઃఆͱར༻Λ໌֬ʹ෼཭Ͱ͖Δ // 初期化中にできることを規定すると… extension Driver where State: Setup { func prepared() -> Driver<Ready> { … } func set(channel: Int) -> Driver { return self } func set(volume: Int) -> Driver { return self } func set(pan: Int) -> Driver { return self } func set(format: Format) -> Driver { return self } func set(route: Route) -> Driver { return self } }

59.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ 1IBOUPN5ZQFͰྲྀΕΛ࡞Δ ⾣ ॳ‫ظ‬ઃఆͱ४උ‫ྃ׬‬Λঢ়ଶͰද‫ݱ‬ ⾣ ϝιουνΣΠϯͷख๏ͰྲྀΕΛ࡞Δ // 初期設定では、順番を気にせず設定できる・補完が効く let driver = Driver<Setup>() .set(format: ulaw) .set(volume: 10) .set(route: .speaker) .prepared() // ここで Driver<Ready>() を返す // 設定完了を宣言 (prepared) して、使い始める driver.start()

60.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ ෳࡶͳྲྀΕ΋‫Ͱޠݴ‬ಋ͚Δ ⾣ ϝιουνΣΠϯͱ‫Ͱܕ‬ಋ͘ɺঢ়ଶભҠ ⾣ ೔ຊ‫ޠ‬༧ଌม‫׵‬Έ͍ͨʹɺิ‫ྲྀͰิީ׬‬ΕΛ༠ಋ let driver = Driver<Setup>() .format // → Driver<FormatSetup> .set(sampleRate: 44100) .set(channelsPerFrame: 2) .general // → Driver<GeneralSetup> .set(volume: 10) .set(route: .speaker) .prepared() // → Driver<Ready>

61.

ঢ়ଶΛอଘ͢ΔΑΓɺྲྀ͢ͷʹ޲͘ʁ 1IBOUPN5ZQFͰͳͯ͘΋ಋ͚Δ ⾣ ఆٛଆ͸ɺ1IBOUPN5ZQFͩͱάϧʔϓ‫͕ײ‬ग़ͯྑ͍ ⾣ ࢖͏ଆ͸ɺ‫ܕ‬ਪ࿦ͷ͓͔͛Ͱɺ‫ܕ‬͸ͳΜͰ΋ྑ͍ let driver = Driver.setup() // → DriverSetup .format .set(sampleRate: 44100) .set(channelsPerFrame: 2) // → FormatSetup .general .set(volume: 10) .set(route: .speaker) // → AudioSetup .prepared() // → Driver

62.

ίϯςΩετํࣜͰ΋࣮‫ݱ‬Մೳ

63.

ίϯςΩετํࣜͰ΋࣮‫ݱ‬Մೳ ઃఆ߲໨Λߏ଄ମͰ༻ҙ͢Δ ⾣ ઃఆͷྲྀΕ͸ɺσʔλߏ଄Ͱಋ͘ ⾣ Կ͔ॳ‫ظ‬஋Λ࣋ͨͤΕ͹ɺ೚ҙ߲໨ʹͰ͖Δ // 設定項目を、初期値を持った構造体で用意して… struct Description { var channel: Int = default var volume: Int = default var pan: Int = default var format: Format = default var route: Route = default }

64.

ίϯςΩετํࣜͰ΋࣮‫ݱ‬Մೳ ߏ଄ମʹ஋ΛͦΖ͑Δ ⾣ ߏ଄ମΛΠϯελϯεԽͯ͠ɺ஋ΛͦΖ͑Δ ⾣ σʔλߏ଄ͷ௨Γʹɺิ‫͘ޮ͕׬‬ let description = Description() description.format.sampleRate = 44100 description.format.channelsPerFrame = 2 description.volume = 10 description.route = .speaker

65.

ίϯςΩετํࣜͰ΋࣮‫ݱ‬Մೳ ઃఆ߲໨Λఴ͑ͯɺΠϯελϯεΛ࡞Δ ⾣ ઃఆ߲໨Λఴ͑ͯॳ‫ظ‬Խͯ͠ɺ‫׬‬੒ ⾣ ‫ܕ‬Λঢ়ଶ੍‫ͳ͍ͳ͠ޚ‬Βɺ͜Ε͕γϯϓϧ // Driver は Description で初期化するようにして… class Driver { init(description: Description) { … } } // 設定項目を渡して、初期化を完成する let driver = Driver(description: description)

66.

‫ܕ‬ͷৼସΛߟ͑Δ

67.

ঢ়ଶͱͯ͠อ͍࣋ͨ͠৔߹

68.

ঢ়ଶͱͯ͠อ͍࣋ͨ͠৔߹ χϡʔτϥϧΛ‫ن‬ఆ͠ɺͦΕΛอ࣋͢Δ ⾣ χϡʔτϥϧঢ়ଶͷσʔλ͚ͩอଘͰ͖Δ ⾣ த్൒୺ͳঢ়ଶΛอଘͰ͖ͳ͍ঢ়‫گ‬Λ࡞ΕΔ class Controller { var environment: Environment<Neutral> }

69.
[beta]
ঢ়ଶͱͯ͠อ͍࣋ͨ͠৔߹

χϡʔτϥϧ࣌͸ɺಡऔઐ༻ʹͯ͠ʜ
⾣ σʔλ͸ɺ‫ج‬ຊঢ়ଶͰ͸ಡΈऔΓ‫ػ‬ೳ͚ͩΛඋ͑Δ
⾣ ฤूঢ়ଶΛऔಘ͢ΔϝιουΛඋ͑Δ

struct Environment<State> {
fileprivate(set) var platform: Platform
fileprivate(set) var version: Double
func startEditing() -> Environment<Editing> {
return Environment<Editing>(
platform: platform, version: version)
}
}

70.
[beta]
ঢ়ଶͱͯ͠อ͍࣋ͨ͠৔߹

ฤू࣌ʹɺॻ͖‫ػ͑׵‬ೳΛఏ‫͢ڙ‬Δͱʜ
⾣ &EJUJOHঢ়ଶͰ͸ɺฤूՄೳͳϝιουΛ࣋ͭ
⾣ χϡʔτϥϧঢ়ଶΛऔಘ͢ΔϝιουΛඋ͑Δ

extension Environment where State: Editing {
mutating func set(platform: Platform) { … }
mutating func set(version: Double) { … }
func endEditing() -> Environment<Neutral> {
return Environment<Neutral>(
platform: platform, version: version)
}
}

71.

ঢ়ଶͱͯ͠อ͍࣋ͨ͠৔߹ ϩʔΧϧείʔϓͰͷฤूΛอূͰ͖Δ ⾣ ฤू࣌ʹऔΓग़͠ɺฤू‫͖ॻʹޙ‬໭ٛ͢຿͕ੜ·ΕΔ ⾣ ௚઀ૢ࡞Ͱ͖ͳ͍ͨΊɺฤूதͷࢀরΛ๷͛Δ func update() { // 編集状態で取り出さないと、書き込めない var environment = self.environment.startEditing() environment.set(platform: .macOS) environment.set(version: Platform.macOS.latest) // ローカルで編集を終了したら、書き戻す self.environment = environment.endEditing() }

72.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

73.
[beta]
Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

Πϯελϯεͷৼସ͕ඞཁ
⾣ 1IBOUPN5ZQF͸ɺҧ͏ΠϯελϯεΛ࡞Γ௚͢
⾣ ঢ়ଶมߋ࣌ʹɺ಺༰ΛҾ͖‫͙ܧ‬ඞཁ͕͋Δ

extension Environment where State: Editing {
var platform: Platform
var version: Double
// 同じ内容の、別インスタンスを作り直している

func endEditing() -> Environment<Neutral> {
return Environment<Neutral>(
platform: platform, version: version)
}

74.
[beta]
Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

಺༰Ҿ‫ܧ‬Λɺ؆୯ʹͰ͖ͳ͍ͩΖ͏͔ʁ
⾣ ෳ੡͢ΔॲཧΛશͯॻ͘ͷ͸ɺखؒͱ࿙Ε͕৺഑
⾣ ϓϩύςΟʔΛ૿΍ͨ࣌͠ͷɺमਖ਼๨Ε΋ෆ҆

extension Environment where State: Editing {
// 内容を原始的にコピーしないといけないとき

func endEditing() -> Environment<Neutral> {
var result = Environment<Neutral>()
result.platform = platform
result.version = version
return result
}

75.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ม‫׵‬ΠχγϟϥΠβʔͰҾ͖‫ํ͙ܧ‬๏

76.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ม‫׵‬ΠχγϟϥΠβʔͰҾ͖‫͙ܧ‬ ⾣ ม‫׵‬ΠχγϟϥΠβʔ͸4XJGUͷ‫׳‬श ⾣ ม‫׵‬ͷ੹೚Λɺ࠷΋͍ۙ̍͠Օॴʹू໿Ͱ͖Δ struct Environment<State> { fileprivate(set) var platform: Platform fileprivate(set) var version: Double } extension Environment { fileprivate init<S>(takeover: Environment<S>) { platform = takeover.platform version = takeover.version } }

77.
[beta]
Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

؆୯ͳखଓ͖Ͱɺঢ়ଶมߋ͕Մೳʹ
⾣ ม‫׵‬ΠχγϟϥΠβʔʹTFMGΛ౉͚ͩ͢
⾣ Ͳͷঢ়ଶ͔Β΋ɺಉ͡ํ๏Ͱม‫׵‬Մೳ

extension Environment where State: Editing {
func endEditing() -> Environment<Neutral> {
return Environment<Neutral>(takeover: self)
}
}

ϓϩύςΟʔ௥Ճ࣌΋ΠχγϟϥΠβʔͷௐ੔͚ͩͰ0,

78.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ಺෦ίϯςΩετͰҾ͖‫ํ͙ܧ‬๏

79.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ಺෦σʔλΛߏ଄ମʹ·ͱΊΔ ⾣ ಺෦σʔλΛͻͱͭͷߏ଄ମͰද‫͢ݱ‬Δ ⾣ Ҿ͖‫͗ܧ‬͸ɺߏ଄ମͷίϐʔੑʹ೚ͤΔ struct Environment<State> { // データをここで集中管理する fileprivate struct Context { var platform: Platform var version: Double } // これだけを引き継げば済む状況を作る fileprivate var _context: Context }

80.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ಺෦ίϯςΩετͰҾ͖‫͙ܧ‬ ⾣ ίϯςΩετΛҾ͖‫͙ܧ‬ΠχγϟϥΠβʔΛ࡞Δ ⾣ ίϯςΩετͷ಺༰͕૿͑ͯ΋ɺෳ੡͠࿙Εͳ͍ extension Environment { fileprivate init(context: Context) { _context = context } }

81.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ؆୯ͳखଓ͖Ͱɺঢ়ଶมߋ͕Մೳʹ ⾣ ม‫׵‬ΠχγϟϥΠβʔʹίϯςΩετΛ౉͚ͩ͢ ⾣ ೚ҙͷίϯςΩετ΁ͷࠩ͠ସ͑΋Մೳ extension Environment where State: Editing { func endEditing() -> Environment<Neutral> { return Environment<Neutral>(context: _context) } } ϓϩύςΟʔΛ௥Ճͯ͠΋ɺશ͕ͯࣗಈͰෳ੡͞ΕΔ

82.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ίϯςΩετ͔Β஋ΛͱΔ‫ػ‬ೳ͕ඞཁ ⾣ ‫ܕࢉܭ‬ϓϩύςΟʔͰɺίϯςΩετΛ஥հ͢Δ ⾣ ๨Εͯ΋ɺ಺෦σʔλͷҾ͖‫͗ܧ‬๨ΕΑΓ͸҆શʁ extension Environment { var platform: Platform { get { _context.platform } set { _context.platform = newValue } } var version: Double { get { _context.version } set { _context.version = newValue } }

83.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ४උθϩͰҾ͖‫ํ͙ܧ‬๏

84.
[beta]
Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

ߏ଄ମΛɺ‫ܕ੍ڧ‬ม‫Ͱ׵‬Ҿ͖‫͛ܧ‬Δ
⾣ શͯͷঢ়ଶͰɺಉ͡ߏ଄͕໿ଋ͞Ε͍ͯΔ
⾣ VOTBGF#JU$BTUͰɺ‫ܕ‬৘ใΛࠩ͠ସ͑Δ

extension Environment where State: Editing {
func endEditing() -> Environment<Neutral> {
// 準備不要で、いきなりビットキャスト可能

return unsafeBitCast(self,
to: Environment<Neutral>.self)
}
}
શͯͷ಺෦σʔλ͕ɺ·Δ͝ͱෳ੡͞ΕΔ

85.
[beta]
Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ

ߏ଄ମΛɺ‫ܕ੍ڧ‬ม‫Ͱ׵‬Ҿ͖‫͛ܧ‬Δ
⾣ ม‫׵‬ΠχγϟϥΠβʔͰɺ‫ܕ੍ڧ‬ม‫Ͱ׵‬΋ྑ͍
⾣ ͪ͜Β΋ಉ༷ɺશͯͷσʔλΛ‫׬‬શʹҾ͖‫͛ܧ‬Δ

extension Environment {
fileprivate init<S>(takeover: Environment<S>) {
self = unsafeBitCast(takeover,
to: Environment.self)
}
}
1IBOUPN5ZQFͳΒͰ͸ͷɺ‫ܕ‬ͷಉҰੑ͕‫͖׆‬Δ৔໘

86.

Πϯελϯεͷ‫͕ؔ͠౉ڮ‬৺Ͳ͜Ζ ΫϥεΛ‫ܕ੍ڧ‬ม‫͢׵‬Δ৔߹ͷ஫ҙ ⾣ ϝλ৘ใ͸ɺ‫ݩ‬ͷ‫ܕ‬ύϥϝʔλʔΛҡ࣋͢Δ ⾣ ࣮ࡍͷΠϯελϯεҎ্ͷμ΢ϯΩϟετ͸‫ݥة‬ let sub: Base = Sub() let base: Base = Base() // 実体が Sub なので、全ての機能が使える let obj: Sub = unsafeBitCast(sub, to: Sub.self) // 実体が Base なので、Sub の機能を使うとクラッシュする let obj: Sub = unsafeBitCast(base, to: Sub.self)

87.

࡞ઓΛ࿅Δ

88.

ঢ়ଶΛ֦ுͰ͖Δʁ

89.

ঢ়ଶΛ֦ுͰ͖Δʁ ઃ‫࣍ܭ‬ୈͰ͸ɺ‫͔ޙ‬Βঢ়ଶ௥Ճ΋Մೳ ⾣ ‫֦ܕ‬ுͰɺ࠷ॳ͔Β͋ͬͨΈ͍ͨʹ௥ՃͰ͖Δ ⾣ ͦΕΛ‫ݟ‬ӽͨ͠ࣄલઃ‫ܭ‬͸ඞཁ class Test: OperationState {} extension HogeOperation where State: Test { func testSomething() {…} } extension HogeOperation where State: Init { func testing() -> HogeOperation<Test> {…} }

90.

ঢ়ଶͷɺαϒλΠϓʜʁ

91.

ঢ়ଶͷɺαϒλΠϓʜʁ ঢ়ଶ͸ɺ‫ܧ‬ঝͰ͖Δ ⾣ ঢ়ଶΛɺΫϥε‫ܧ‬ঝͰද‫͖Ͱݱ‬Δ ⾣ ‫ܧ‬ঝ‫͋ʹݩ‬Δɺ͢΂ͯͷ‫ػ‬ೳΛҾ͖‫͛ܧ‬Δ // Test 状態を Prepared から継承させれば… class Test: Prepared {} // Test には Prepared の機能も備わる extension HogeOperation where State: Prepared { func execute() {…} } extension HogeOperation where State: Test { func testSomething() {…} }

92.

ͻͱ·ͣɺఁ࡯ऴྃ

93.

ͱʹ͔͘‫͑ݴ‬Δ͜ͱ 1IBOUPN5ZQFʹग़⁊͓͔͑ͨ͛Ͱ ϏϧυλΠϜͰͷ࣮ߦ੍‫ʹޚ‬΋ҙ͕ࣝ޲͘Α͏ʹͳͬͨ ‫҆ܕ‬શͷͻͱͭͷද‫ݱ‬ख๏ͱͯ͠༗༻

94.

͸͡Ίͯ1IBOUPNͱૺ۰ͯ͠ ҋӢʹಆ͍Λ௅ΜͰΈͨ࿩ ͜ΕͰ1IBOUPNͱ΋ಆ͑ͦ͏ʁ Πϥετग़లIUUQ‫ق‬અͷΠϕϯτDPN

95.

&OKPZ4XJGU 5IBOLZPV ͸͡Ίͯ1IBOUPNͱૺ۰ͯ͠ ҋӢʹಆ͍Λ௅ΜͰΈͨ࿩ &;/&5‫۽‬୩༑޺ IUUQF[OFUKQ ⾣ 1IBOUPN5ZQF ⾣ ‫ܕ‬ͷফ໓ੑ΍ɺ୅ସද‫ݱ‬Λఁ࡯ ⾣ ‫ܕ‬ͷಉҰੑͱΠϯελϯεͷৼସ ⾣ ࣄ‫ޙ‬ͷ֦ுͱαϒλΠϓ