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

DSL Design (Kotlin Budapest User Group meetup - September)

Marton Braun
September 28, 2017

DSL Design (Kotlin Budapest User Group meetup - September)

A talk presenting the basics of what a DSL is, what use cases there are for them, and looking at some of the design choices we can make while creating one.

Marton Braun

September 28, 2017
Tweet

More Decks by Marton Braun

Other Decks in Programming

Transcript

  1. DSL design
    Márton Szabolcs Braun
    zsmb13
    [email protected] zsmb13

    View full-size slide

  2. About this talk
    • What’s a DSL
    • Relevant Kotlin features
    • Common examples
    • My own experience
    • Design demo
    • How to implement DSLs

    View full-size slide

  3. Domain Specific Languages
    • Programming languages
    • Specialized to solve problems in a particular domain
     HTML
     Gradle build language
    • Often in a declarative style

    View full-size slide

  4. DSL ingredients in Kotlin
    • Extension functions
    • Extension properties
    • Lambdas with receivers
    • Operator overloading
     Unary operators
     invoke operator
    • Infix functions
    • @DslMarker annotation

    View full-size slide

  5. Common examples

    View full-size slide

  6. Anko https://github.com/Kotlin/anko
    verticalLayout {
    val name = editText()
    button("Say Hello") {
    onClick {
    toast("Hello, ${name.text}!")
    }
    }
    }

    View full-size slide

  7. html {
    body {
    div {
    a("http://kotlinlang.org") {
    target = ATarget.blank
    +"Main site"
    }
    }
    }
    }
    kotlinx.html https://github.com/Kotlin/kotlinx.html

    View full-size slide

  8. Gradle Script Kotlin
    android {
    buildToolsVersion("25.0.0")
    compileSdkVersion(23)
    defaultConfig {
    minSdkVersion(15)
    targetSdkVersion(23)
    applicationId = "com.example.myapp"
    versionCode = 1
    versionName = "1.0"
    }
    }
    https://github.com/gradle/kotlin-dsl
    android {
    compileSdkVersion 23
    buildToolsVersion "25.0.0"
    defaultConfig {
    minSdkVersion 15
    targetSdkVersion 23
    applicationId "com.example.myapp"
    versionCode 1
    versionName "1.0"
    }
    }
    Kotlin Groovy

    View full-size slide

  9. object Cities : Table() {
    val id = integer("id").autoIncrement().primaryKey()
    val name = varchar("name", 50)
    }
    transaction {
    val munichId = Cities.insert {
    it[name] = "Munich"
    } get Cities.id
    Cities.insert {
    it[name] = "Prague"
    }
    }
    Exposed https://github.com/JetBrains/Exposed

    View full-size slide

  10. My experience

    View full-size slide

  11. MaterialDrawerKt https://github.com/zsmb13/MaterialDrawerKt
    drawer {
    closeOnClick = false
    sectionHeader("Standard badges") { divider = false }
    primaryItem("Primary") {
    badge("111")
    iicon = FontAwesome.Icon.faw_heart
    }
    sectionHeader("Customized badges")
    primaryItem("Custom 1") {
    badge("111") {
    color = 0xFF0099FF
    colorPressed = 0xFFCC99FF
    cornersDp = 0
    paddingHorizontalDp = 25
    }
    iicon = FontAwesome.Icon.faw_heart
    selectable = false
    }
    }

    View full-size slide

  12. Tests for Twitter responses
    Status
    MediaEntity
    Array< >
    URLEntity
    Array< >
    HashtagEntity
    Array< >
    UserMentionEntity
    Array< >
    val status: Status = mock()
    whenever(status.text) doReturn mockText
    whenever(status.mediaEntities) doReturn mockMediaEntities
    whenever(status.urlEntities) doReturn mockUrls
    whenever(status.userMentionEntities) doReturn mockUserMentionEntities
    whenever(status.hashtagEntities) doReturn mockHashtagEntities

    View full-size slide

  13. Tests for Twitter responses
    val status: Status = mock()
    whenever(status.text) doReturn mockText
    whenever(status.mediaEntities) doReturn mockMediaEntities
    whenever(status.urlEntities) doReturn mockUrls
    whenever(status.userMentionEntities) doReturn mockUserMentionEntities
    whenever(status.hashtagEntities) doReturn mockHashtagEntities
    Status
    MediaEntity
    Array< >
    URLEntity
    Array< >
    HashtagEntity
    Array< >
    UserMentionEntity
    Array< > val entity: UserMentionEntity = mock()
    whenever(entity.start) doReturn mockStart
    whenever(entity.end) doReturn mockEnd
    whenever(entity.id) doReturn mockId
    whenever(entity.screenName) doReturn mockScreenName
    val entity: MediaEntity = mock()
    whenever(entity.start) doReturn mockStart
    whenever(entity.end) doReturn mockEnd
    whenever(entity.url) doReturn mockUrl
    val entity: URLEntity = mock()
    whenever(entity.start) doReturn mockStart
    whenever(entity.end) doReturn mockEnd
    whenever(entity.url) doReturn mockUrl
    whenever(entity.displayURL) doReturn mockDisplayUrl
    whenever(entity.expandedURL) doReturn mockExpandedUrl
    val entity: HashtagEntity = mock()
    whenever(entity.start) doReturn mockStart
    whenever(entity.end) doReturn mockEnd
    whenever(entity.text) doReturn mockText
    val h1 = createHashtag(1, 4, "cool")
    val h2 = createHashtag(6, 12, "awesome")
    val hashtags = arrayOf(h1, h2)
    val status = createStatus(hashtags, mentions, ...)

    View full-size slide

  14. tests {
    testCase("emoji and text") {
    input("hello world")
    expected("hello world")
    }
    testCase("long, complicated status") {
    input("hello t.co/a t.co/b t.co/m1 t.co/c t.co/m2 ") {
    url(9 to 15, "t.co/a", "a.com", "a.com")
    url(19 to 25, "t.co/b", "b.com", "b.com")
    media(29 to 36, "t.co/m1")
    url(40 to 46, "t.co/c", "c.c.c.com", "c.c.c.com")
    media(50 to 57, "t.co/m2")
    }
    expected("hello a.com b.com c.c.c.com ") {
    url(13 to 18, "t.co/a", "a.com", "a.com")
    url(26 to 31, "t.co/b", "b.com", "b.com")
    url(47 to 56, "t.co/c", "c.c.c.com", "c.c.c.com")
    }
    }
    }
    Tests for Twitter responses

    View full-size slide

  15. Resources
    • Village DSL
     https://github.com/zsmb13/VillageDSL
    • Type safe builders (official documentation)
     https://kotlinlang.org/docs/reference/type-safe-builders.html
    • Designing a DSL in Kotlin (Nicolas Fränkel)
     https://youtu.be/fD3OqrAeaWo
    • Creating DSL's in idiomatic Kotlin (Hadi Hariri)
     https://youtu.be/GjGQpSFieXA

    View full-size slide

  16. Photo:
    Alexey Sergeev
    DSL design
    zsmb13
    [email protected] zsmb13

    View full-size slide