Careeroza
infix and Operator Functions in DSLs
Readable APIs
infix functions can be called without dot and parentheses (a to b). operator functions let you use symbols (+, [], in, ..). Used carefully, they make test assertions, money and date code read like English.
Example
data class Money(val paise: Long) {
operator fun plus(o: Money) = Money(paise + o.paise)
operator fun times(n: Int) = Money(paise * n)
operator fun compareTo(o: Money) = paise.compareTo(o.paise)
override fun toString() = "Rs ${paise / 100}"
}
val Int.rupees get() = Money(this * 100L)
infix fun <T> T.shouldBe(expected: T) {
println(if (this == expected) "PASS: $this" else "FAIL: expected $expected but was $this")
}
class Cart {
private val items = linkedMapOf<String, Money>()
operator fun set(name: String, price: Money) { items[name] = price }
operator fun get(name: String) = items[name]
operator fun contains(name: String) = name in items
val total get() = items.values.fold(0.rupees) { a, b -> a + b }
}
fun main() {
val cart = Cart()
cart["Notebook"] = 60.rupees * 3
cart["Pen"] = 20.rupees
println("Total: ${cart.total}")
("Pen" in cart) shouldBe true
cart["Notebook"] shouldBe 180.rupees
(cart.total > 150.rupees) shouldBe true
}Output
Total: Rs 200 PASS: true PASS: Rs 180 PASS: true
DSLs You Already Use
// Gradle Kotlin DSL
dependencies {
implementation("io.ktor:ktor-server-core:3.0.0")
}
// Ktor routing
routing {
get("/products/{id}") { call.respond(repo.find(call.parameters["id"]!!)) }
}
// Jetpack Compose is a DSL built on @Composable lambdas
Column { Text("Hello"); Button(onClick = {}) { Text("OK") } }