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

JavaZone 2022 - Building Kotlin DSL

Anton Arhipov
September 08, 2022

JavaZone 2022 - Building Kotlin DSL

Kotlin provides many features that make your code look like a domain-specific language. These features make Kotlin an excellent choice in cases where we want to express program logic declaratively. The approach is already adopted in many tools and frameworks: you can describe build logic in Gradle with Kotlin, Spring WebFlux uses syntax features for its APIs, etc. This session will teach you how to create type-safe DSLs in Kotlin. We will look at a few practical examples and produce a simple DSL.

#kotlin

Anton Arhipov

September 08, 2022
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. Kotlin DSL
    Building
    @antonarhipov

    View full-size slide

  2. @antonarhipov

    View full-size slide

  3. Null-safety
    Coroutines
    Multiplatform
    Syntax
    Why Kotlin?

    View full-size slide

  4. Null-safety
    Coroutines
    Multiplatform
    Syntax
    Why Kotlin?

    View full-size slide

  5. Null-safety
    Coroutines
    Multiplatform
    Syntax
    Why Kotlin?

    View full-size slide

  6. Null-safety
    Coroutines
    Multiplatform
    Syntax
    Why Kotlin?

    View full-size slide

  7. Null-safety
    Coroutines
    Multiplatform
    Syntax
    Why Kotlin?
    DSL

    View full-size slide

  8. “Domain-speci
    fi
    c”, i.e.

    View full-size slide

  9. tailored for a
    speci
    fi
    c task
    “Domain-speci
    fi
    c”, i.e.

    View full-size slide

  10. External VS Internal

    View full-size slide

  11. External VS Internal

    View full-size slide

  12. External VS Internal

    View full-size slide

  13. External VS Internal

    View full-size slide

  14. External VS Internal

    View full-size slide

  15. They all


    look


    similar!

    View full-size slide

  16. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  17. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  18. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  19. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  20. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  21. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  22. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  23. Let’s write


    some code!
    https://github.com/antonarhipov/kotlin-dsl-examples

    View full-size slide

  24. Let’s write


    some code!
    https://github.com/antonarhipov/kotlin-dsl-examples

    View full-size slide

  25. Type-safe builders
    https://kotlinlang.org/docs/reference/type-safe-builders.html

    View full-size slide

  26. final ClientBuilder builder = new ClientBuilder();


    builder.setFirstName("Anton");


    builder.setLastName("Arhipov");


    final TwitterBuilder twitterBuilder = new TwitterBuilder();


    twitterBuilder.setHandle("@antonarhipov");


    builder.setTwitter(twitterBuilder.build());


    final CompanyBuilder companyBuilder = new CompanyBuilder();


    companyBuilder.setName("JetBrains");


    companyBuilder.setCity("Tallinn");


    builder.setCompany(companyBuilder.build());


    final Client client = builder.build();


    System.out.println("Created client is: " + client);


    val client = createClient {


    firstName = "Anton"


    lastName = "Arhipov"


    twitter {


    handle = "@antonarhipov"


    }


    company {


    name = "JetBrains"


    city = "Tallinn"


    }


    }


    println("Created client is: " + client.consoleString)


    View full-size slide

  27. //extension property


    val Client.consoleString: String


    get() = "${twitter.handle} ${company.name}"


    //extension method


    fun Client.toConsoleString(): String {


    return "${twitter.handle} ${company.name}"


    }


    View full-size slide

  28. fun createClient(c: ClientBuilder.() -> Unit): Client {


    val builder = ClientBuilder()


    c(builder)


    return builder.build()


    }


    fun ClientBuilder.company(t: CompanyBuilder.() -> Unit) {


    company = CompanyBuilder().apply(t).build()


    }


    fun ClientBuilder.twitter(t: CompanyBuilder.() -> Unit) {


    twitter = TwitterBuilder().apply(t).build()


    }


    Lambda with receiver
    Extension methods

    View full-size slide

  29. In
    fi
    x notation
    https://kotlinlang.org/docs/reference/functions.html

    View full-size slide

  30. dateTime = LocalDateTime.of(2018, Month.DECEMBER, 11, 0, 0)
    dateTime = 11 December 2018 at (14 hh 0)
    infix fun Int.December(n: Int) : LocalDate {


    return LocalDate.of(n, Month.DECEMBER, this)


    }


    infix fun LocalDate.at(n: Pair): LocalDateTime {


    return this.atTime(n.first, n.second)


    }


    infix fun Int.hh(n: Int): Pair {


    return Pair(this, n)


    }


    View full-size slide

  31. Context Receivers
    KEEP-259
    Experimental

    View full-size slide

  32. context(DateContext)


    @DateDsl


    infix fun Int.March(n: Int): LD = LD.of(n, Month.MARCH, this)
    class DateContext
    val client = createClient {


    // ..
    .

    dob = 24 March 2000


    }


    24 March 2000
    fun client(block: context(DateContext) ClientBuilder.()
    -
    >
    Unit): Client {


    val builder = ClientBuilder()


    with(DateContext()) {


    block(builder)


    }


    return builder.build()


    }


    Context object
    Context requirement
    Context requirement
    Context scope
    The function is available in
    the context scope
    The function is not available,
    missing DateContext

    View full-size slide

  33. T.() -> Unit

    View full-size slide

  34. Kotlin {


    YouTube = "youtube.com/kotlin"


    Slack = "slack.kotl.in"


    }
    me {


    name = "Anton Arhipov"


    twitter = "@antonarhipov"


    slides = speakerdeck.com/antonarhipov


    }
    books { courses {

    View full-size slide