iOSDC Japan 2018 @ukitakaSwiftͷܕγεςϜʹೖ͢Δlib/Semaͷา͖ํ
View Slide
ࣗݾհYuki Takahashi @ukitaka▸ iOS Engineer @ Mercari Fukuoka Office▸ SwiftͷίϯύΠϥɺಛʹܕγεςϜʹڵຯ͕͋Γ·͢ɻ▸ ͨ·ʹϒϩάQiitaΛॻ͍ͯ·͢ɻ
ࠓͷςʔϚSwiftͷܕγεςϜʹೖ͢Δ▸ Swiftͷܕͷ͜ͱΛͬͱਂ͘Γ͍ͨਓΛλʔήοτͱͯ͠ɺSwiftίϯύΠϥͷ࣮ΛಡΈ࢝ΊΒΕΔͱ͜Ζ·Ͱ͍࣋ͬͯ͘͜ͱΛඪ▸ 2ํ͔ΒͷΞϓϩʔν▸ SwiftίϯύΠϥͷ࣮ΛಡΉ▸ SwiftͷܕγεςϜͷཧΛΔ→ શମΛ၆ᛌ͠ɺ࠷ॳͷҰาͷ͓ख͍
ࠓͷςʔϚΞδΣϯμ▸ SwiftͷܕγεςϜͷಛΛΔ▸ Swiftͷܕਪͱͦͷσόοάํ๏ΛΔ▸ SwiftͷܕγεςϜͷ࣮ΛಡΉ▸ SwiftͷܕγεςϜͷཧΛΔ
SwiftͷܕγεςϜͷಛΛΔ
SwiftͷܕγεςϜͷಛΛΔSwiftͷܕγεςϜͷಛ▸ ܕਪ▸ δΣωϦΫε▸ αϒλΠϐϯά▸ ଘࡏܕ (Existential type)▸ ܕΫϥεɾݶఆܕ (Qualified type)
SwiftͷܕγεςϜͷಛΛΔܕਪ▸ Hindley-MilnerϥΠΫͳ੍(Constraint)ϕʔεͷܕਪ▸ ྫ͑มͷܕΛ໌ࣔ͠ͳͯ͘ࠨล͔Βਪͯ͘͠ΕΔ▸ ӈล͔Βࠨล͍͚Δ▸ ೖʹݶΒͣɺ͍Ζ͍Ζͳͱ͜ΖͰܕΛ໌ࣔ͠ͳͯ͘Α͍❌ ؔͷҾɾฦͷܕলུͰ͖ͳ͍ɺ1expression/1statementʹด͍ͯ͡Δ
SwiftͷܕγεςϜͷಛΛΔδΣωϦΫε▸ ίʔυੜϑΣʔζ·ͰؚΊͨίϯύΠϥͷ࣮ͱͯ͠໘ന͍▸ ܕγεςϜͱͯ͋͠Δҙຯཧ௨Γ▸ ܕਪΛͬͯଟ૬ੑΛ࣮ݱ͢Δ▸ ͨͩ͠ܕύϥϝʔλʹର͢Δ੍पΓޙड़ͷݶఆܕ(Qualified type)ͱؔ࿈ͯ͘͠Δ
SwiftͷܕγεςϜͷಛΛΔଘࡏܕ (Existential Type)▸ = ܕͱͯ͠ͷprotocol▸ SwiftଘࡏܕΛ͋Δҙຯతʹѻ͑Δ͍͠ݴޠ▸ ଘࡏܕͩͱҙࣝͤͣʹ͑Δݴޠઃܭ▸ Opening existential͕ಋೖ͞ΕΔͱଘࡏܕͱͳʹ͔ΛΒͳ͍ͱཧղͮ͠Β͍͜ͱ͋Δ͔͠Εͳ͍→ গͳ͘ͱprotocolܕ = ଘࡏܕͰ͋Δͱ͍͏͜ͱΛ಄ͷย۱ʹஔ͍͓ͯ͘ͱྑ͍
SwiftͷܕγεςϜͷಛΛΔܕΫϥεɾݶఆܕ(Qualified Type)▸ = ܕύϥϝʔλͷ੍ͱͯ͠ͷprotocol▸ T: Equatable▸ Conditional Conformance▸ ݶఆܕʮܕΫϥεΛܕγεςϜͰѻ͏ʯͨΊͷཧ▸ ܕ্ͷड़ޠʹΑ੍ͬͯΛ͔͚Δ▸ Jones, Mark P. Qualified Types: Theory andPractice. Cambridge University Press, 1994.
SwiftͷܕγεςϜͷಛΛΔαϒλΠϐϯά▸ αϒλΠϐϯάࣗମଞͷݴޠʹݟΒΕΔ͕ɺSwiftͷͦΕ͔ͳΓಛత▸ classͱͦͷܧঝ͚ؔͩͰͳ͍▸ Optionalʹର͢ΔαϒλΠϐϯά▸ TT?ͷαϒλΠϓ▸ Existentialʹର͢ΔαϒλΠϐϯά▸ T <: U, U: P 㱺 T <: P→ ҉มΛࢧ͑ΔΈ
SwiftͷܕγεςϜͷಛΛΔSwiftͷܕγεςϜ͕͍࣋ͬͯͳ͍ͷ (ൈਮ)❌ શͳܕਪ❌ ߴΧΠϯυଟ૬ (Haskell, ScalaͳͲ)❌ Rank2Ҏ্ͷଟ૬❌ ҙͷδΣωϦοΫͳܕʹର͢Δڞมɾมͷࢦఆ→ Կ͔ͱͷτϨʔυΦϑͳͷͰɺ͋Δ͔Βྑ͍ͱ͍͏Θ͚Ͱͳ͍Swift͜ͷลΓͷόϥϯε͕ͱΕ͍ͯΔྑ͍ݴޠ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔҙຯղੳɾܕਪɾܕݕࠪ▸ ʮܕʯͷνΣοΫίϯύΠϥͷҙຯղੳϑΣʔζͰߦΘΕΔ▸ SwiftίϯύΠϥͷҙຯղੳϑΣʔζͰ͍ͬͯΔ͜ͱͷ9ׂ͘Β͍͕ܕݕࠪ▸ ܕਪ =ʮܕݕ͕ࠪ௨ΔΑ͏ͳܕΛ࠶ߏங͢Δ͜ͱʯͳͷͰ͋Δҙຯηοτ▸ ܕਪ͕ԿΛ͍ͯ͠Δͷ͔͕Θ͔ΕܕγεςϜ͕Θ͔Δ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔίϯύΠϥͷίʔυΛಡΉલʹ▸ ͍͖ͳΓίϯύΠϥͷίʔυΛಡΉͷͪΐͬͱେม▸ ·ͣσόοάͷͨΊͷίϚϯυΛ͓ͬͯ͘ͱίʔυΛಡ·ͣʹڍಈΛ֬ೝͰ͖Δ▸ લఏࣝͱͯ͠ίϯύΠϧͱASTͷϑΣʔζΛ֬ೝ͓ͯ͘͠Swift AST AST(typed)lib/Parse lib/Sema͕͜͜ܕʹؔ͢ΔΞϨίϨ͕ߦΘΕΔͱ͜Ζ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔASTΛग़ྗ͢ΔίϯύΠϥΦϓγϣϯ2ͭ% swiftc -helpOVERVIEW: Swift compilerUSAGE: swiftc [options] MODES:-dump-ast Parse and type-check input file(s) and dump AST(s)-dump-parse Parse input file(s) and dump AST(s)Swift AST AST(typed)-dump-parse -dump-astlib/Sema
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔASTΛग़ྗ͢ΔίϯύΠϥΦϓγϣϯ2ͭ% swiftc -helpOVERVIEW: Swift compilerUSAGE: swiftc [options] MODES:-dump-ast Parse and type-check input file(s) and dump AST(s)-dump-parse Parse input file(s) and dump AST(s)Swift AST AST(typed)Γ͍ͨͷ͜ͷաఔͷdumpํ๏lib/Sema
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔ-debug-constraints▸ ܕਪɺܕݕࠪͷաఔΛग़ྗ͢ΔΦϓγϣϯ▸ Constraints = ܕਪ࣌ʹ͏ʮAͱBͷܕಉ͡ʯͷΑ͏ͳ੍(Constraint)ͷ͜ͱ▸ ܕγεςϜlib/SemaΛཧղ͢Δ্Ͱͷ࠷ॏཁίϯύΠϥΦϓγϣϯSwift AST AST(typed)lib/Parse lib/Sema-debug-constraints
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔ-debug-constraints% swiftc \-frontend \-typecheck \-debug-constraints \test.swift
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔ-debug-constraintslet i = 42→ ग़ྗͰ͖ΔΑ͏ʹͳͬͨͷͰ͔͜͜ΒಡΈํΛղઆ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔ1. ܕ͕໌ࣔ͞Ε͍ͯͳ͍ͱ͜ΖΛܕม(Type Variable)Ͱ͓͘2. ܕมͷ੍(Constraint)Λੜ͢Δ3. ੍Λղ͍ͯղ(Solution)Λݟ͚ͭΔ4. ͦͷղΛݩͷASTʹద༻ͭͭ͠ඞཁͳॻ͖͑(Rewrite)Λߦ͏
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔ$T1 $T0let i = 421. ܕ͕໌ࣔ͞Ε͍ͯͳ͍ͱ͜ΖΛܕม(Type Variable)Ͱ͓͘
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔlet i = 422. ܕมͷ੍(Constraint)Λੜ͢Δ$T0 Ϧςϥϧ$T0 $T1ʹมͰ͖Δ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔlet i = 423. ੍Λղ͍ͯղ(Solution)Λݟ͚ͭΔ$T1 = Int $T0 = Int
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔlet i: Int = Int2048(_builtinIntegerLiteral: 42)4. ͦͷղΛݩͷASTʹద༻ͭͭ͠ඞཁͳॻ͖͑(Rewrite)Λߦ͏Ϧςϥϧ͕ؔbuiltinݺͼग़͠ʹܕ͕ܾ·ͬͨঢ়ଶ※ ASTΛ۩จ๏ʹͨ͠Πϝʔδ
Swiftͷܕਪͱͦͷσόοάํ๏ΛΔܕਪɾܕݕࠪͷྲྀΕΛΔ1. ܕ͕໌ࣔ͞Ε͍ͯͳ͍ͱ͜ΖΛܕม(Type Variable)Ͱ͓͘2. ܕมͷ੍(Constraint)Λੜ͢Δ3. ੍Λղ͍ͯղ(Solution)Λݟ͚ͭΔ4. ͦͷղΛݩͷASTʹద༻ͭͭ͠ඞཁͳॻ͖͑(Rewrite)Λߦ͏→ ͜ͷྲྀΕͰग़ྗ͞Ε͍ͯΔ
SwiftͷܕγεςϜͷ࣮ΛಡΉ
SwiftͷܕγεςϜͷ࣮ΛಡΉlib/Sema▸ Sema = ҙຯղੳ (Semantic Analysis)▸ ओʹܕਪܕݕࠪΛ୲͢ΔϞδϡʔϧ
SwiftͷܕγεςϜͷ࣮ΛಡΉओཁͳΫϥε▸ TypeChecker → ܕݕࠪ୲▸ TypeCheck*.cppʹׂ࣮͕͞Ε͍ͯΔ▸ ConstraintSystem → ܕਪ୲▸ CS*.cpp ʹׂ࣮͕͞Ε͍ͯΔ
SwiftͷܕγεςϜͷ࣮ΛಡΉओཁͳΫϥε▸ TypeChecker͕ࣜ͝ͱʹConstraintSystemΛΠϯελϯεԽ͍ͯͬͯ͠ΔΠϝʔδ
SwiftͷܕγεςϜͷ࣮ΛಡΉConstraintSystemͷࣄ - ੍ੜ▸ createTypeVariableͰܕมΛ࡞Δ▸ addConstraintͰ੍Λੜˍཧ͢Δ▸ ConstraintKindͰ੍ͷछྨΛࢦఆ▸ ੍ConstraintGraphͱݺΕΔάϥϑͰཧ ੍ੜͷྫ
SwiftͷܕγεςϜͷ࣮ΛಡΉConstraintSystemͷࣄ - ੍ͷ୯ҰԽ▸ solveͰ੍Λղ͘▸ جຊతʹղͷީิΛͲΜͲΜͨΊ͍ͯ͘͠
SwiftͷܕγεςϜͷ࣮ΛಡΉConstraintSystemͷࣄ - ղͷద༻ͱॻ͖͑▸ applySolutionͷதͰExprRewriterͱ͍͏ΫϥεΛͬͯASTΛॻ͖͑ͯܕͷใΛຒΊΔ
SwiftͷܕγεςϜͷ࣮ΛಡΉlib/SemaΛͬͱಡΉʹ▸ ͜͜ʹॻ͍ͨͷେ·͔ͳྲྀΕͷΈ▸ overloadͷղܾɺϝιουݺͼग़͠ͷղܾͳͲ·ͩ·ͩॏ͍ͨ͘͞Μ͋Δ▸ ͦΕΒجຊతʹ-debug-constraintsʹදΕΔ͜ͱ͕ଟ͍ͷͰɺग़ྗͱ࣮ΛோΊͳ͕Β͕ΜΔ▸ XcodeͰ্खʹσόοά͠Α͏ʂ
SwiftͷܕγεςϜͷཧΛΔ
SwiftͷܕγεςϜͷཧΛΔSwiftͷܕγεςϜͷཧΛΔ▸ ཧΛΕ࣮͕ಡΈ͘͢ͳΔ▸ SwiftίϯύΠϥͷ࣮ෳࡶʹབྷΈ߹͍ͬͯΔ͕ɺجຊతʹ͍͔ͭ͘ͷτϐοΫͷू·Γɻͦͯ͠୯ମͰݟΔͱཧ௨Γ࣮͞Ε͍ͯΔ߹͕ଟ͍ɻ▸ ֓೦Λ͍ͬͯΔ͚ͩͰ͍ͩͿೖΓ͍͢▸ Opening existentialͷΑ͏ʹͦͦ֓೦ΛΒͳ͍ͱҙຯ͕Θ͔Βͳ͍ͷ͋Δ→ ৄࡉͳղઆͰ͖ͳ͍ͷͰɺֶͼํͷΈհ
SwiftͷܕγεςϜͷཧΛΔܕγεςϜೖ(TaPL)▸ Types and Programming Language (TaPL)▸ ܕͳ͠ͷϥϜμܭࢉͷΑ͏ͳجૅతͳͱ͜Ζ͔Βঃʑʹݱͷϓϩάϥϛϯάݴޠ͕࣋ͭΑ͏ͳػೳΛ͚Ճ͍͑ͯ͘▸ 1ষແྉͰެ։͞Ε͍ͯΔʂʮܕʯͱԿ͔ΛΔʹ࠷ߴͷࢿྉ→ SwiftΛΔͨΊʹͲ͏ಡΊྑ͍ʁ
SwiftͷܕγεςϜͷཧΛΔTaPLͷา͖ํ▸ લఏͱͯ͠ɺͯ͢ͷষΛಡΉඞཁͳ͍▸ 9ষ·Ͱجૅͱͯ͠ಡΜͰ͓͘ͱΑͦ͞͏▸ લʮཧͷষ → OCamlʹΑΔ࣮ͷষʯͷ܁Γฦ͠ͳͷͰ࣮ΛSwiftͰͬͯΈΔͱ͍͏ͷྑ͍ख▸ ઌ΄ͲݟͨΑ͏ͳSwiftͷܕγεςϜͷಛΛѻ͍ͬͯΔͷ15ষɺ22ষɺ24ষ͋ͨΓܕγεςϜೖ−ϓϩάϥϛϯάݴޠͱܕͷཧ− ংจΑΓҾ༻
SwiftͷܕγεςϜͷཧΛΔୈ22ষ ܕ࠶ߏங▸ ܕ࠶ߏங = ܕਪ▸ ܕਪͱSwift͕࣋ͭΑ͏ͳδΣωϦΫεʹ͍ͭͯऔΓѻ͍ͬͯΔষ▸ SwiftͷδΣωϦοΫͳؔܕਪͱηοτͰఏڙ͞Ε͍ͯΔػೳ (letଟ૬) ͱ͍͏͜ͱ͕Θ͔ΔThe secret life of types in Swifthttps://medium.com/@slavapestov/the-secret-life-of-types-in-swift-ff83c3c000a5ܕγεςϜೖ−ϓϩάϥϛϯάݴޠͱܕͷཧ− ୈ22ষʮܕ࠶ߏஙʯΑΓҾ༻
SwiftͷܕγεςϜͷཧΛΔୈ15ষ ෦ܕ͚▸ ෦ܕ͚ = αϒλΠϐϯά▸ ͋Δܕͱ͋Δܕ͕αϒλΠϓؔͰ͋Δ͔Ͳ͏͔ɺͦͷܕγεςϜͰͷʮܾΊʯͷͩͱ͍͏͜ͱ͕Θ͔ΕΑͦ͞͏▸ 15.5અͷʮܕڧ੍ҙຯʯͷͱ͜Ζ·͞ʹSwiftίϯύΠϥͰߦΘΕ͍ͯΔ͜ͱ͕ॻ͍ͯ͋ΔͷͰඞಡܕγεςϜೖ−ϓϩάϥϛϯάݴޠͱܕͷཧ− ୈ15ষʮ෦ܕ͚ʯΑΓҾ༻
SwiftͷܕγεςϜͷཧΛΔୈ24ষ ଘࡏܕ▸ λΠτϧ௨Γଘࡏܕ(Existential type)Λѻ͏ষ▸ ଘࡏܕ͕ʮ͋ΔܕͱͦͷܕΛͬͨܕʯͷɺଘࡏܕͷʮ͋Δܕ͕۩ମతʹͳʹ͔ + ͦͷʯͷϖΞͰ͋Δͱ͍͏ͱ͜Ζ͔͑ͭ͞ΊΕSwiftͷଘࡏܕා͘ͳ͍ϖΞͬΆ͍งғؾܕγεςϜೖ−ϓϩάϥϛϯάݴޠͱܕͷཧ− ୈ24ষʮଘࡏܕʯΑΓҾ༻
SwiftͷܕγεςϜͷཧΛΔSwiftʹؔ͋Γͦ͏Ͱؔͳ͍ষ▸ ୈ23ষ શশܕ▸ ͍ΘΏΔδΣωϦΫεͷ͜ͱͩͱࢥͬͯಡΉͱϋϚΔ▸ Swift͜ͷষͰऔΓ্͛ΒΕ͍ͯΔΑ͏ͳλΠϓͷڧྗͳδΣωϦΫεΛ࣋ͨͳ͍▸ ୈ26ষ ༗քྔԽ▸ ͺͬͱݟ T: EquatableͷΑ͏ͳ੍ʹ͍ͭͯͷཧతഎܠ͕ॻ͍ͯ͋ΔΑ͏ʹΈ͑Δ͕ɺ࣮ؔͳ͍ (see: ݶఆܕ)▸ ༗քྔԽαϒλΠϐϯάʹΑ੍ͬͯΛ͔͚Δɺݶఆܕܕ্ͷड़ޠͰ੍Λ͔͚Δͱ͍͏ҧ͍
SwiftͷܕγεςϜͷཧΛΔ͠ܕγεςϜͷೖʹ࠳ંͨ͠Β▸ ࠳ં͚ͨ͠ͲͦΕͰTaPLಡΈ͍ͨͱ͍͏ͱ͍͏ํɺ(ه߸)ཧֶ͔Β͵Δͬͱೖ͍ͬͯ͘ͱΑͦ͞͏▸ ࠳ંͯ͜͠ΜͳྲྀΕͰ࠶ೖ͠·ͨ͠
·ͱΊ
·ͱΊSwiftͷܕγεςϜʹೖ͢Δʹ▸ -debug-constraintsΛ͍͜ͳͯ͠ܕਪͷڍಈΛѲͭͭ͠ɺίϯύΠϥͷιʔείʔυΛಡΈਐΊΑ͏▸ ཧ࣮ΛಡΈղ͘ώϯτͱͯ͠༗ޮͳ͜ͱ͋ΔɺTaPLΛಡΜͰΈΑ͏
·ͱΊSwiftͷܕγεςϜʹೖ͢Δʹ▸ ༏ͯ͘͠ฏͰ༗ҙٛͳswiftcษڧձ͋Γ·͢
͋Γ͕ͱ͏͍͟͝·ͨ͠