Kotlin DSL
in under an hour
@antonarhipov
Yet
another
Yet
DSLanother
Yet
DSLanother
Yet
talk
Domain-specific, i.e.
tailored for the
specific task
Domain-specific, i.e.
External
External VS Internal
External VS Internal
External VS Internal
Internal
createHTML().html {
head {
+"Hello!"
}
body {
ul {
p {
+"This is my awesome text!"
}
}
}
}
kotlinx.html
https://github.com/Kotlin/kotlinx.html
Anko
https://github.com/Kotlin/anko
verticalLayout {
padding = dip(30)
val name = editText {
hint = "Name"
textSize = 24f
}
val pwd = editText {
hint = "Password"
textSize = 24f
}
button("Login") {
textSize = 26f
onClick { toast("Hello, ${name.text}!") }
}
Gradle Kotlin DSL
https://github.com/gradle/kotlin-dsl
plugins {
java
kotlin("jvm") version "1.2.70"
}
group = "org.arhan"
version = "1.0-SNAPSHOT"
repositories {
maven { setUrl("http://dl.bintray.com/kotlin/kotlin-eap") }
jcenter()
}
dependencies {
val kotlinx_html_version = "0.6.11"
compile(kotlin("stdlib-jdk8"))
compile("org.jetbrains.kotlinx:kotlinx-html-jvm:${kotlinx_html_version}")
testCompile("junit", "junit", "4.12")
Exposed
https://github.com/JetBrains/Exposed
object Cities : Table() {
val id = integer("id").autoIncrement().primaryKey() // Column<Int>
val name = varchar("name", 50) // Column<String>
}
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]}")
}
}
https://github.com/nfrankel/kaadin
Kaadin
theme = "valo"
verticalLayout(margin = true, spacing = true) {
tabSheet {
tab("Interactions") {
accordion {
tab("Button", HAND_O_RIGHT) {
horizontalLayout(true, true) {
button()
button("Label")
button("Label", HAND_O_RIGHT)
button("Click me", onClick = { show("Clicked") })
button("Click me", HAND_O_RIGHT, { show("Clicked") })
}
}
k8s-kotlin-dsl
https://github.com/fkorotkov/k8s-kotlin-dsl
val client = DefaultKubernetesClient().inNamespace("default")
client.extensions().ingresses().createOrReplace(
newIngress {
metadata {
name = "example-ingress"
}
spec {
backend {
serviceName = "example-service"
servicePort = IntOrString(8080)
}
}
}
)
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) {}
fun main(args: Array<String>) {
embeddedServer(Jetty, commandLineEnvironment(args)).start(wait = true)
}
fun Application.main() {
install(DefaultHeaders)
install(CallLogging)
routing {
get("/") {
call.respondHtml {
head {
title { +"Ktor App" }
}
body {
p {
+"Hello from Ktor!"
}
}
Ktor
They all
look
similar
foo {
bar {
baz = "Hello!"
qux = quux {
corge = "Blah"
}
}
}
foo {
bar {
baz = "Hello!"
qux = quux {
corge = "Blah"
}
}
}
foo {
bar {
baz = "Hello!"
qux = quux {
corge = "Blah"
}
}
}
foo {
bar {
baz = "Hello!"
qux = quux {
corge = "Blah"
}
}
}
foo {
bar(grault = 1) {
baz = "Hello!"
qux = quux {
corge = "Blah"
}
}
}
foo {
bar(grault = 1) {
baz = "Hello!"
qux = quux {
corge = Blah()
}
}
}
foo {
bar(grault = 1) {
baz = "Hello!"
qux = quux {
corge = Blah()
}
}
}
foo {
bar(grault = 1) {
baz = "Hello!"
qux = quux {
corge = Blah()
}
}
}
Let’s write
some code!
https://github.com/jonnyzzz/kotlin-dsl-demo
Let’s write
some code!
https://github.com/jonnyzzz/kotlin-dsl-demo
Type-safe builders
https://kotlinlang.org/docs/reference/type-safe-builders.html
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)
//extension property
val Client.consoleString: String
get() = "${twitter.handle} ${company.name}"
//extension method
fun Client.toConsoleString(): String {
return "${twitter.handle} ${company.name}"
}
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
twitter {
handle = "@antonarhipov"
company {
name = "JetBrains"
city = "Tallinn"
}
}
@DslMarker
annotation class ClientDsl
@ClientDsl
class CompanyBuilderDsl : CompanyBuilder()
@ClientDsl
class TwitterBuilderDsl : TwitterBuilder()
twitter {
handle = "@antonarhipov"
company {
name = "JetBrains"
city = "Tallinn"
}
}
Scope control
Infix notation
https://kotlinlang.org/docs/reference/functions.html
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<Int, Int>): LocalDateTime {
return this.atTime(n.first, n.second)
}
infix fun Int.hh(n: Int): Pair<Int, Int> {
return Pair(this, n)
}
T.() -> Unit
me {
name = "Anton Arhipov"
twitter = "@antonarhipov"
}
books { courses {
Kotlin {
Try = "try.kotlinlang.org"
Slack = "slack.kotl.in"
}

Devoxx Ukraine 2018 - Kotlin DSL in under an hour