Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Having fun with DSLs

Having fun with DSLs

Kotlin Type-safe builders explained!

Giacomo Bresciani

March 15, 2018
Tweet

More Decks by Giacomo Bresciani

Other Decks in Programming

Transcript

  1. A COMPUTER PROGRAMMING LANGUAGE OF LIMITED EXPRESSIVENESS FOCUSED ON A

    PARTICULAR DOMAIN. l DOMAIN-SPECIFIC LANGUAGE:
  2. “The idea of a DSL is to target a particular

    kind of problem rather than a general purpose language that can be used to address any kind of problem. In other words with a DSL you are writing a programming language by your own to solve a particular problem you are facing.” - Martin Fowler DOMAIN-SPECIFIC LANGUAGE
  3. DOMAIN-SPECIFIC LANGUAGE Internal DSLs A particular idiom of writing code

    in the host language External DSLs A completely separate language that is parsed into data that the host language can understand
  4. DSLS BENEFITS • Flexibility and customization • Readability and ease

    of maintainability • Easy to read or modify by non-tech people
  5. form { section("Section 1") { picker(key = "key1") { label

    = "Picker Label" placeHolder = "Select an option" possibleValues = listOf( "1" keyTo "Option 1", "2" keyTo "Option 2", "3" keyTo "Option 3" ) } input(key = "key2") { label = "Input Label" rules = { listOf(MinLength(3)) } } } section("Section 2") { checkbox(key = "key3") { label = "Mandatory check" rules = { listOf(ShouldBeTrue()) } } toggle(key = "key5") { label = "Another toggle" } } } FORM EXAMPLE
  6. FORM EXAMPLE form { section("Section 1") { picker(key = "key1")

    { label = "Picker Label" placeHolder = "Select an option" possibleValues = listOf( "1" keyTo "Option 1", "2" keyTo "Option 2", "3" keyTo "Option 3" ) } input(key = "key2") { label = "Input Label" rules = { listOf(MinLength(3)) } } } section("Section 2") { checkbox(key = "key3") { label = "Mandatory check" rules = { listOf(ShouldBeTrue()) } } toggle(key = "key5") { label = "Another toggle" } } }
  7. KOTLIN FEATURES RECAP • High-order functions and lambdas • Extension

    functions • Function Literals with Receiver
  8. HIGH-ORDER FUNCTIONS & LAMBDAS fun transformWith( path: String, function: (String)

    -> List<String> ): List<String> { return function(path) } { path: String -> path.split("/") } transformWith("some/path/to", { path: String -> path.split("/") }) transformWith(“some/path/to”) { path -> path.split("/") }
  9. EXTENSION FUNCTIONS fun String.transformWith( function: (String) -> List<String> ): List<String>

    { return function(this) } "some/path/to".transformWith { path: String -> path.split("/") }
  10. FUN SUMMARY // lambda { s: String -> s.split("/") }

    // is to fun function(s: String): List<String> { return s.split("/") } // as val functionLiteralWithReceiver: String.() -> List<String> = { this.split("/") } // is to fun String.extensionFunction(): List<String> { return function(this) }
  11. WRAPPING UP form { picker(key = "key1") { label =

    "Picker Label" placeHolder = "Select an option" possibleValues = listOf( "1" keyTo "Option 1", "2" keyTo "Option 2", "3" keyTo "Option 3" ) } } data class FormModel( val fields: MutableList<FieldModel> = mutableListOf() ) data class PickerModel( var label: String, var placeHolder: String = "", var possibleValues: List<KeyValue> ): FieldModel
  12. WRAPPING UP fun form(init: FormModel.() -> Unit): FormModel { val

    form = FormModel() form.init() return form }
  13. WRAPPING UP fun form(init: FormModel.() -> Unit): FormModel { val

    form = FormModel() form.init() return form } fun FormModel.picker( key: String, init: PickerModel.() -> Unit ): PickerModel { val picker = PickerModel(title) picker.init() fields.add(picker) return picker }
  14. PROBLEM picker(key = "key1") { label = "Picker Label" picker("key2")

    {} } data class FormModel(…) data class FieldModel(…)
  15. @DSLMARKER picker(key = "key1") { label = "Picker Label" picker("key2")

    {} } @ModelMarker data class FormModel(…) @ModelMarker data class FieldModel(…) @DslMarker annotation class ModelMarker
  16. ANKO verticalLayout { val name = editText() button("Say Hello") {

    onClick { toast("Hello, ${name.text}!") } } } • DSL to build Android layouts