Kotlin DSL for Gradle Kotlin DSL Is Not Only Kotlin DSL for Gradle ▸ *Kotlin DSL* in this presentation does not mean Gradle's one ▸ Kotlin DSL for Gradle is just a DSL in Kotlin for Gradle ▸ Contracts, coroutines, etc. are also Kotlin DSL 6 Kotlin DSL Kotlin DSL for Gradle ͷ͜ͱ͚ͩ͡Όͳ͍ ͜ͷൃදͰͷ Kotlin DSL Gradle ͷͷ͚ͩΛࢦ͢Θ͚͡Όͳ͍ Kotlin DSL for Gradle Kotlin Ͱॻ͔Εͨ Gradle ༻ͷ DSL Ͱ͋Δͱ͍͏͚ͩ Contracts, coroutines ͱ͔ Kotlin DSL
Kotlin DSL for Gradle Kotlin DSL Is Not Only Kotlin DSL for Gradle ▸ *Kotlin DSL* in this presentation does not mean Gradle's one ▸ Kotlin DSL for Gradle is just a DSL in Kotlin for Gradle 7 Go to Next questions!
computer language specialized to a particular application domain ▸ In contrast: a general purpose language like Kotlin, Java 14 ref: https://en.wikipedia.org/wiki/Domain-specific_language υϝΠϯݻ༗ݴޠ ಛఆͷΞϓϦέʔγϣϯυϝΠϯʹಛԽͨ͠ίϯϐϡʔλݴޠ ରরతͳͷ Kotlin, Java ͷΑ͏ͳ൚༻ݴޠ
particular application domain ▸ In contrast: a general purpose language like Kotlin, Java ▸ What's a motivation to introduce/need DSL? 15 The base knowledges of DSL ref: https://en.wikipedia.org/wiki/Domain-specific_language DSL Λಋೖ͢Δɺඞཁͱ͢ΔϞνϕʔγϣϯͳʹ͔
▸ More readable, understandable, fluent ▸ Use smart and/or minimum APIs for the domain ▸ Improve productivity and reduce human errors ▸ Get a power of type system etc. 16 The base knowledges of DSL ͳΜͰ DSL Λ͏ͷ͔ ෳࡶͳίʔυΛγϯϓϧʹ͢ΔͨΊ ಡΈ͍͢ɺཧղ͍͢͠ɺྲྀெͳ interface ಛఆυϝΠϯʹର͢ΔεϚʔτͰɺඞཁ࠷ݶͳ API ͕ར༻Ͱ͖Δ ੜ࢈ੑͷ্ώϡʔϚϯΤϥʔͷݮগͷͨΊ ܕγεςϜͷྗΛಘͨΓͩͱ͔
DSL ▸ External: A language that's parsed independently of the host general purpose language ▸ Internal: A particular form of API in the host general purpose language for the domain 18 The base knowledges of DSL ref: https://martinfowler.com/books/dsl.html υϝΠϯݻ༗ݴޠಛੑ ֎෦ DSL ͱ෦DSL ϗετͱͳΔ൚༻ݴޠͱಠཱͯ͠ύʔε͞ΕΔ DSL ϗετͱͳΔ൚༻ݴޠͷதͰɺಛఆͷ API ͷܗࣜΛఏڙ͢Δ DSL
CSS, Regular expressions ▸ Internal DSL ▸ HTML, Mocking Libraries, DI container ▸ Kotlin DSL ▸ NOT a special edition of Kotlin 21 The base knowledges of DSL Kotlin ͷಛผͳੜͱ͔͍͏Θ͚Ͱͳ͍
purpose language ▸ Type checking ▸ Syntax ▸ Syntactic extensions ▸ Compiler extensibility and interpolation 22 The base knowledges of DSL ෦ DSL Λࢧ͑Δٕज़ҎԼʹґଘ ϗετͱͳΔ൚༻ݴޠ ܕݕࠪ جૅߏจ ߏจ֦ு ίϯύΠϥ֦ுੑิؒࢠ
purpose language Kotlin ▸ Type checking Static type checking ▸ Syntax Lambda expressions, etc. ▸ Syntactic extensions Method extension, operator overloading, etc. ▸ Compiler extensibility and/or interpolation Compiler plugins etc. 23 The base knowledges of DSL
HTML domain ▸ Generate DOM tree from a Kotlin code 25 Type safe builder pattern, lambda expressions, functions with receiver, higher-order functions, operator overloading, DSLMarker, etc. The base knowledges of DSL
Specifications/techniques of Kotlin DSL based on levels ▸ Quick tips for DSL development 26 ▸ NOTE: DSL in following slides means Internal DSL unless specified Kotlin DSL ͷ༷ٕज़ΛϨϕϧผͰ DSL ։ൃͷͨΊͷͪΐͬͱͨ͠ tips ͔ͬ͜Β໌هͳ͘ DSL ͱ͍ͬͨΒ෦ DSL Ͱ͢
▸ In contrast: Dynamic type checking ▸ Allow know type violations before executing 30 Techniques of Kotlin DSL - Getting Started - 1/3 ίʔυղੳϕʔεͷܕ҆શੑݕࠪ ରর : ಈతܕݕࠪ ࣮ߦલʹܕҧΛΔ͜ͱ͕Ͱ͖Δ
▸ In contrast: Dynamic type checking ▸ Allow know type violations before executing 31 Groovy : no error but fail at runtime Techniques of Kotlin DSL - Getting Started - 1/3 Τϥʔͳ͍͕ɺ࣮ߦ࣌ʹམͪΔ ίʔυղੳϕʔεͷܕ҆શੑݕࠪ ରর : ಈతܕݕࠪ ࣮ߦલʹܕҧΛΔ͜ͱ͕Ͱ͖Δ
▸ In contrast: Dynamic type checking ▸ Allow know type violations before executing 32 Groovy : no error but fail at runtime Kotlin : a compilation error Techniques of Kotlin DSL - Getting Started - 1/3 ίϯύΠϧΤϥʔ Τϥʔͳ͍͕ɺ࣮ߦ࣌ʹམͪΔ ίʔυղੳϕʔεͷܕ҆શੑݕࠪ ରর : ಈతܕݕࠪ ࣮ߦલʹܕҧΛΔ͜ͱ͕Ͱ͖Δ
this scope of a function ▸ Groovy also can do this but Java cannot. ▸ Function Type : Receiver.(Argument) -> Return ▸ Great help for block-code and fluent style coding 40 Techniques of Kotlin DSL - Getting Started - 3/3 ؔͷ this είʔϓ(receiver)Λࢦఆ͢Δ͜ͱ͕Ͱ͖Δ e.g. Groovy Ͱ͖Δ͚ͲɺJava Ͱ͖ͳ͍ ؔܕදه ϒϩοΫίʔυදݱྲྀெͳදݱʹศར
Better Development? ▸ Only techniques described before allow create a simple DSL 43 Techniques of Kotlin DSL - Getting Started - Closing ྑ͍։ൃͷͨΊʹ͜ΕͰेͩΖ͏͔
knowledges I have explained ▸ It's enough if you want type-safe and/or lambda's elegant style. ▸ Let's check what techniques can improve usability of Kotlin DSL and how we can create Kotlin DSL for existing libraries/APIs. 44 Techniques of Kotlin DSL - Getting Started - Closing ࠓ·ͰͷࣝͰɺεΫϥον͔Β؆୯ʹ DSL ࡞ΕΔ ܕ҆શͰ͋ͬͨΓɺϥϜμࣜʹΑΔελΠϧͰॻ͖͍͚ͨͩͳΒे
knowledges I have explained ▸ It's enough if you want type-safe and/or lambda's elegant style. ▸ Let's check what techniques can improve usability of Kotlin DSL and how we can create Kotlin DSL for existing libraries/APIs. 45 Techniques of Kotlin DSL - Getting Started - Closing ͰͲΜͳςΫχοΫ͕ Kotlin DSL ͷརศੑදݱྗΛ͋͛Δ͔ɺͲ͏ͬͯ Kotlin DSL Λ࡞͍͚ͬͯΔͷ͔ΛݟͯΈ·͠ΐ͏
However, we cannot avoid member visibility restrictions ▸ The benefits of Extension Method for DSL ▸ Can apply the techniques which I will explain later ▸ Can create DSLs without modifying 3rd party libraries 49 Techniques of Kotlin DSL - Intermediate - 1/5 ܧঝͳ͠ʹ৽͍͠ϝϯόʔϝιουΛఆٛͰ͖Δ ͨͩ͠ϝϯόʔՄࢹੑӽ͑ΒΕͳ͍ ར for DSL ͜ͷ͋ͱઆ໌͢ΔςΫχοΫΛ͋ͱ͔Βద༻͢Δ͜ͱ͕Ͱ͖Δ 3rd party ϥΠϒϥϦΛमਖ਼ͤͣʹ DSL ΛߏஙͰ͖Δ
+"any text" means appending text to the node ▸ + is shorter than *text* 52 Techniques of Kotlin DSL - Intermediate - 2/5 https://github.com/Kotlin/kotlinx.html +<ҙͷςΩετ> ͱ͍͏ه๏ͦͷͷ͕ϊʔυͷςΩετՃͱ͍͏ૢ࡞Λද͍ͤͯΔ + text ΑΓ type ͕গͳ͍
We can assign a logic to several operators like +, -... ▸ The benefits of Operator Overloading for DSL ▸ Basically, operators are shorter than method names ▸ A meaning of an operation is clear 53 Techniques of Kotlin DSL - Intermediate - 2/5 ։ൃऀԋࢉࢠΛΦʔόʔϩʔυ͢Δ͜ͱ͕Ͱ͖Δ ͭ·ΓɺಠࣗͷϩδοΫΛطଘͷԋࢉࢠʹ͕͋ͯ͑Δ རӹ for DSL ͍͍ͩͨͷέʔεͰԋࢉࢠͷํ͕ϝιου໊ΑΓͯ͘ࡁΉ ԋࢉࢠ͔Β͘Δૢ࡞ͷҙຯ͕໌ྎ
argument* ▸ Can omit a dot and parentheses from a method call ▸ The benefits of Infix Notation for DSL ▸ Would be more fluent style ▸ Can reduce domain knowledge 57 Techniques of Kotlin DSL - Intermediate - 3/5 Recever infix-function argument ͷܗͰݺͼग़͕͠Մೳ υοτׅހΛলུͯ͠ϝιουίʔϧͰ͖Δ རӹ for DSL ͬͱྲྀெͳදݱΛٻͰ͖Δ υϝΠϯࣝΛinterface͔ΒݮΒ͢͜ͱ͕Ͱ͖Δ
an existing function which accepts closure ▸ It's dynamically generated and be configured by a passed closure 59 Techniques of Kotlin DSL - Intermediate - 4/5 Groovy code https://github.com/gradle/gradle debug ΫϩʔδϟΛड͚औΔΑ͏ͳطଘͷؔͰͳ͍ ಈతʹੜ͞Εɺ͞ΕͨΫϩʔδϟΛݩʹઃఆ͞ΕΔ
▸ Operators/syntax which Java does not implement manually will be available if a method satisfies a convention ▸ Index-access, invoke, range operator... ▸ The benefits of Method Convention for DSL ▸ Easy to create lambda expressions-based builder by overloading invoke ▸ Can hide domain knowledge bypass a common operator/syntax in Kotlin 62 Techniques of Kotlin DSL - Intermediate - 4/5 ԋࢉࢠΦʔόʔϩʔυͷҰछ ϝιου͕نΛຬͨ͢͜ͱͰɺJava ͕ಠࣗͰఆٛͰ͖ͳ͍Α͏ͳԋࢉࢠߏจ͕͑ΔΑ͏ʹͳΔ IndexϕʔεͷΞΫηεɺinvokeɺൣғԋࢉࢠ རӹ for DSL invoke Λఆٛ͢Δ͜ͱͰɺϥϜμࣜϕʔε(ϒϩοΫίʔυ)ͷϏϧμʔͳͲ͕࡞Γ͍͢ Kotlin ͰΑ͘ΘΕΔԋࢉࢠߏจͷதʹɺυϝΠϯࣝΛӅṭ͢Δ͜ͱ͕Ͱ͖Δ
is low-level ▸ A simple command-query API sequence is required 64 Techniques of Kotlin DSL - Intermediate - 5/5 https://github.com/chibatching/Kotpref SharedPreferences API ڃ ୯७ͳίϚϯυΫΤϦAPI Λॱ൪ʹୟ͘ඞཁ͕͋Δ
API and domain knowledge ▸ Writing a value to a property will save it to the preferences but it's hidden 65 Techniques of Kotlin DSL - Intermediate - 5/5 https://github.com/chibatching/Kotpref https://github.com/chibatching/Kotpref ڃ API υϝΠϯࣝΛӅͤΔ ྫ͑propertyʹΛೖ͢Δͱ SharedPreferences ʹॻ͖ࠐΉ͕ɺͦͷϩδοΫશʹӅṭ͞Ε͍ͯΔ
▸ The benefits of Delegations for DSL ▸ Can hide domain knowledge ▸ Effective for DRY when using read and write operations to properties 66 Techniques of Kotlin DSL - Intermediate - 5/5 ϓϩϖςΟΞΫηε͞ΕͨΒଞͷΦϒδΣΫτʹॲཧΛҕৡ͢Δ རӹ for DSL υϝΠϯࣝΛӅͤΔ ϓϩύςΟʹର͢ΔಡΈॻ͖ૢ࡞ʹؔ͢Δ DRY ʹศར
specify a receiver of SAM so Kotlin cannot use functions with receiver without extension methods 70 Java code Call Container#execute from Kotlin Techniques of Kotlin DSL - Expertise - 1/2 Java SAM ͷϨγʔόΛࢦఆͰ͖ͳ͍ɻͦͷͨΊ Kotlin Ϩγʔό͖ͭؔΛͦͷ··(֦ுؔͳ͠)Ͱѻ͏͜ͱ͕Ͱ͖ͳ͍ɻ
the plugin ▸ An argument of SAM will be a receiver in Kotlin! 71 Techniques of Kotlin DSL - Expertise - 1/2 Example - Kotlin DSL for Java Code SAM interface ʹΞϊςʔγϣϯ͚ͭͯɺϓϥάΠϯʹ͓Βͤ͢Δ͚ͩ SAM ͷҾ͕ Kotlin ͰϨγʔόʔʹ
▸ For Kotlin code, but need to modify Java code ▸ The benefits of SAM-with-receiver ▸ Useful when non-Kotlin libraries assume usability of Kotlin DSL ▸ Avoid a bit awkward API in Kotlin 72 Techniques of Kotlin DSL - Expertise - 1/2 https://github.com/JetBrains/kotlin/tree/master/plugins/sam-with-receiver SAM ม࣌ͷϨγʔόʔΛ͍͡ΕΔ Kotlin code ͷͨΊͷػೳ͚ͩͲɺJava ଆΛमਖ਼͢Δඞཁ͕͋Δ རӹ for DSL Kotlin ͡Όͳ͍ϥΠϒϥϦ͕ Kotlin DSL ͷͨΊͷརศੑΛߟ͑Δͱ͖ʹ༗༻ Kotlin Ͱͪΐͬͱ͗ͪ͜ͳ͍ײ͡ͷ API ʹͳΔͷΛճආͰ͖Δ
▸ Action API is widely used so SAM-with-receiver is better than extensions 73 https://github.com/gradle/gradle/commit/18aebdba33cd9e1be966cc286a11d3ce86a28e4f Techniques of Kotlin DSL - Expertise - 1/2 https://github.com/gradle/gradle Action API ΊͬͪΌΘΕͯΔͷͰɺSAM-with-receiver ͷํ͕֦ுؔΑΓྑ͍
superclasses (and functions if necessary) 76 Techniques of Kotlin DSL - Expertise - 2/2 Example - Pseudo Dom Tree Builder DslMarker ͷΞϊςʔγϣϯΛϨγʔόʔͷΫϥεεʔύʔΫϥεʹ͚ͭΔ
I know ▸ Add a constraint of a caller scope and can raise errors if invalid ▸ The benefits of DslMarker for DSL ▸ This is required to make your DSL safe ▸ Be developers' help because IntelliJ highlight marked functions 78 Techniques of Kotlin DSL - Expertise - 2/2 ΔݶΓɺKotlin ʹ͓͚Δ DSLಛԽͨ͠།Ұͷػೳ ݺͼग़͠ͷείʔϓʹ੍Λ͚ͭΔ͜ͱ͕Ͱ͖ͯɺҧͯͨ͠ΒΤϥʔͱͰ͖Δ རӹ for DSL DSL ͷ҆શੑΛߴΊΔͨΊʹඞਢ ։ൃऀͷॿ͚ʹͳΔɻIntelliJ ϚʔΫ͞Εͨؔʹରͯ͠ಠࣗͷϋΠϥΠτΛ͔͚ͯ͘ΕΔ
DslMarker to build DOM tree correctly ▸ html, head, body are marked functions so highlighted 79 Techniques of Kotlin DSL - Expertise - 2/2 kotlinx.html ͪΖΜར༻͍ͯͯ͠ɺ͜ΕͰਖ਼͘͠ DOM tree Λ࡞ΕΔΑ͏ʹ͍ͯ͠Δ html, head ͱ͔͕ϋΠϥΠτ͞ΕͯΔΑͶ
stuff is undocumented ▸ Complex logic is hard to be implemented ▸ Maintainability... ▸ DslMarker needs be annotated to classes, so it's unavailable for existing libraries 80 Techniques of Kotlin DSL - Expertise - Closing ίϯύΠϥʔϓϥάΠϯυΩϡϝϯτ͞Εͯͳ͍ ੍ݶ ෳࡶͳϩδοΫݫ͍͠ อकੑΣɾɾɾ DslMarker ΫϥεʹΞϊςʔγϣϯΛ͚ͭΔඞཁ͕͋ͬͯɺͭ·ΓطଘϥΠϒϥϦͰ͑ͳ͍
▸ The concepts of the interface design are different ▸ DSL is focusing on the domain ▸ DSL is well-designed API set for the domain but also limited ▸ We should not assume DSL can work as general APIs 82 Quick Tips 1/4 ٕज़తʹͳΜ͔ҧ͍ͱ͔ͳ͍ API ͱ DSL ͷҧ͍ interface ͷઃܭίϯηϓτ͕ҟͳΔ DSL υϝΠϯʹॏ͖Λஔ͍ͯΔ DSL υϝΠϯʹରͯ͠Α͘࿅ΒΕͨ API ηοτ͚ͩͲɺͦͷ੍ݶ͋Δ DSL ͕൚༻తͳ API ͱͯ͠ಈ͘ͱఆ͢Δ͖Ͱͳ͍
Aggregate existing APIs by extension method ▸ Use Operator overloading, Infix operators, Method conventions ▸ Create DTOs if you would like to use DslMarker 83 ֦ுؔͰطଘ API Λू͢Δͱ͜Ζ͔Βߟ͑Δ طଘϥΠϒϥϦͷ Kotlin DSL ͷద༻ ԋࢉࢠΦʔόʔϩʔυɺதஔه๏ɺϝιουنΛ͍͖ͬͯ·͠ΐ͏ DslMarker Λ͍͍ͨͳΒࣗલͰ Data transfer object Λ࡞ͬͯରԠ͠·͠ΐ͏
DSL and Other JVM Languages ▸ Java -> Kotlin DSL ▸ Use SAM with receiver ▸ Kotlin DSL -> Other JVM languages ▸ Provide method chaining interface because of functions with receiver issue ▸ Provide alternative non-inline APIs because of inline features' availability ▸ Split API for other JVM languages and Kotlin DSL 84 Kotlin DSL ΛJava ϥΠϒϥϦʹద༻͢Δέʔε Ͳ͏ͬͯ Kotlin DSL ͱଞJVMݴޠͱͰརศੑΛҡ࣋͢Δ͔ ͪΌΜͱ sam-with-receiver Λ͍·͠ΐ͏ Kotlin DSL ͷ interface ΛଞJVMݴޠ͔Β͏έʔε Ϩγʔόʔ͖ͭؔϦςϥϧ͕͋ΔͷͰɺϝιουνΣʔϯࣜͷ interface ͳͲΛผ్༻ҙ͢Δ inline ܥػೳͷՄࢹੑ͕͋ΔͷͰɺinline ͡Όͳ͍ API Λผ్ఏڙ͢Δ ଞJVMݴޠ༻్ͷ API ͱ Kotlin DSL ͚࣮ͯ͢Δ
DSL and Other JVM Languages ▸ Java -> Kotlin DSL ▸ Use SAM with receiver ▸ Kotlin DSL -> Other JVM languages ▸ Provide method chaining interface because of receiver issue ▸ Provide alternative non-inline APIs because of inline vibisility ▸ Split API for other jvm languages and Kotlin DSL ▸ Other JVM languages -> Kotlin DSL : I don't know, sorry 85 JavaҎ֎ͷJVMݴޠʹ Kotlin DSL ΛషΔͱ͖ : ͢Έ·ͤΜɺܦݧෆͰΘ͔Μͳ͍Ͱ͢
but improves safety! ▸ Kotlin DSL can extend existing libraries with only a few constraints ▸ We can co-exist usability for the both of Kotlin and other JVM languages ▸ If you work hard 90 Closing DslMarker ͚͕ͩ Kotlin DSL ༻ͷಛԽػೳɻ҆શੑΛ্Ͱ͖Δ(͍·͠ΐ͏) Kotlin DSL طଘϥΠϒϥϦΛͪΐͬͱ੍͖͚ͨͭͩ͠Ͳ֦ுͰ͖Δ Kotlin DSL ͱଞJVMݴޠͰͷརศੑڞଘՄೳ(ͨͩ͠ؤுΕ)
Fowler with R. Parsons ▸ DSLs in Action by D. Ghosh ▸ Dsl Engineering: Designing, Implementing and Using Domain-specific Languages by M. Voelter ▸ Kotlin in Action by D. Jemerrov and S. Isakova ▸ Web/Blog ▸ Catalog of DSL Patterns https://martinfowler.com/dslCatalog/ ▸ Kotlin DSL: From Theory to Practice https://dzone.com/articles/kotlin-dsl-from-theory-to-practice ▸ Writing a Kotlin DSL (series) https://proandroiddev.com/writing-dsls-in-kotlin-part-1-7f5d2193f277 ▸ Idiomatic Kotlin. Best Practices. https://phauer.com/2017/idiomatic-kotlin-best-practices/ ▸ and more... 91 Closing