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

Kotlin DSL in under an hour, DevoxxUK 2023

Kotlin DSL in under an hour, DevoxxUK 2023

Anton Arhipov

May 09, 2023
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. Kotlin DSL
    in under an hour
    @antonarhipov

    View full-size slide

  2. Null-safety


    Coroutines


    Multiplatform


    Syntax
    Why Kotlin?

    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?
    DSL

    View full-size slide

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

    View full-size slide

  8. tailored for a


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

    View full-size slide

  9. External VS Internal

    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. Exposed
    https://github.com/JetBrains/Exposed
    object Cities : Table() {


    val id = integer("id").autoIncrement().primaryKey()
    //
    Column


    val name = varchar("name", 50)
    //
    Column


    }


    View full-size slide

  15. Exposed
    https://github.com/JetBrains/Exposed
    object Cities : Table() {


    val id = integer("id").autoIncrement().primaryKey()
    //
    Column


    val name = varchar("name", 50)
    //
    Column


    }


    transaction {


    create (Cities)


    val tallinnId = Cities.insert {


    it[name] = "Tallinn"


    } get Cities.id


    for (city in Cities.selectAll()) {


    println("${city[Cities.id]}: ${city[Cities.name]}")


    }


    }


    View full-size slide

  16. Kotlin DSL in TeamCity
    project {


    vcsRoot(ApplicationVcs)


    buildType {


    id("Application")


    name = "Application"


    vcs { root(ApplicationVcs) }


    artifactRules = "target/*jar"


    steps {


    maven { goals = "clean package" }


    }


    triggers { vcs {} }


    dependencies {


    snapshot(Library) {}




    View full-size slide

  17. fun main() {


    embeddedServer(Netty, port = 8080, host = “0.0.0.0",


    module = Application
    ::
    module).start(wait = true)


    }


    fun Application.main() {


    install(DefaultHeaders)


    install(CallLogging)


    routing {


    get("/") {


    call.respondHtml {


    head {


    title { +"Ktor App" }


    }


    body {


    p {


    +"Hello from Ktor!"


    }




    Ktor + kotlinx.html

    View full-size slide

  18. fun main() {


    embeddedServer(Netty, port = 8080, host = “0.0.0.0",


    module = Application
    ::
    module).start(wait = true)


    }


    fun Application.main() {


    install(DefaultHeaders)


    install(CallLogging)


    routing {


    get("/") {


    call.respondHtml {


    head {


    title { +"Ktor App" }


    }


    body {


    p {


    +"Hello from Ktor!"


    }




    Ktor + kotlinx.html

    View full-size slide

  19. fun main() {


    embeddedServer(Netty, port = 8080, host = “0.0.0.0",


    module = Application
    ::
    module).start(wait = true)


    }


    fun Application.main() {


    install(DefaultHeaders)


    install(CallLogging)


    routing {


    get("/") {


    call.respondHtml {


    head {


    title { +"Ktor App" }


    }


    body {


    p {


    +"Hello from Ktor!"


    }




    Ktor + kotlinx.html

    View full-size slide

  20. They all


    look


    similar!

    View full-size slide

  21. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  22. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  23. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  24. foo {


    bar {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  25. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = "Blah"


    }


    }


    }

    View full-size slide

  26. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  27. foo {


    bar(grault = 1) {


    baz = "Hello!"


    qux = quux {


    corge = Blah()


    }


    }


    }

    View full-size slide

  28. Let’s write


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

    View full-size slide

  29. Let’s write


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

    View full-size slide

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

    View full-size slide

  31. 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

  32. //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

  33. 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 functions

    View full-size slide

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

    View full-size slide

  35. 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

  36. Context Receivers
    KEEP-259
    Experimental

    View full-size slide

  37. context(DateContext)


    @DateDsl


    infix fun Int.March(n: Int): LD = LD.of(n, Month.MARCH, this)
    class DateContext Context object
    Context requirement

    View full-size slide

  38. context(DateContext)


    @DateDsl


    infix fun Int.March(n: Int): LD = LD.of(n, Month.MARCH, this)
    class DateContext
    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

    View full-size slide

  39. context(DateContext)


    @DateDsl


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


    // ..
    .

    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

  40. T.() -> Unit

    View full-size slide

  41. kotlin {


    youtube = "youtube.com/kotlin"


    slack = "slack.kotl.in"


    }
    me {


    name = "Anton Arhipov"


    twitter = "@antonarhipov"


    slides = speakerdeck.com/antonarhipov


    code = github.com/antonarhipov


    }

    View full-size slide