O que é DSL em Kotlin?

DSL significa Domain-Specific Language — uma linguagem específica de domínio. Em Kotlin, você pode criar DSLs usando lambdas com receiver e extension functions, resultando em código que parece quase uma linguagem natural para determinada tarefa.

Se você já usou Gradle com Kotlin Script ou escreveu testes com Kotest, já viu DSLs em ação.

Exemplo simples: construtor de HTML

class HTML {
    private val elementos = mutableListOf<String>()

    fun head(titulo: String) {
        elementos.add("<head><title>$titulo</title></head>")
    }

    fun body(conteudo: Body.() -> Unit) {
        val body = Body()
        body.conteudo()
        elementos.add("<body>${body.render()}</body>")
    }

    fun render() = "<html>${elementos.joinToString("")}</html>"
}

class Body {
    private val itens = mutableListOf<String>()

    fun p(texto: String) { itens.add("<p>$texto</p>") }
    fun h1(texto: String) { itens.add("<h1>$texto</h1>") }

    fun render() = itens.joinToString("")
}

fun html(bloco: HTML.() -> Unit): String {
    val pagina = HTML()
    pagina.bloco()
    return pagina.render()
}

E o uso fica assim:

fun main() {
    val pagina = html {
        head("Kotlin Brasil")
        body {
            h1("Bem-vindo!")
            p("Aprenda Kotlin de um jeito brasileiro.")
        }
    }
    println(pagina)
}

Repare como o código fica expressivo — quase como escrever HTML de verdade.

A mágica: lambdas com receiver

O segredo das DSLs em Kotlin é a lambda com receiver. Quando você declara HTML.() -> Unit, está dizendo que dentro do bloco, o this é uma instância de HTML. Isso permite chamar os métodos diretamente, sem prefixo.

Exemplo prático: configuração

class DatabaseConfig {
    var host = "localhost"
    var porta = 5432
    var nome = ""
}

fun database(config: DatabaseConfig.() -> Unit): DatabaseConfig {
    return DatabaseConfig().apply(config)
}

fun main() {
    val db = database {
        host = "db.kotlin.dev.br"
        porta = 5433
        nome = "kotlin_brasil"
    }
    println("${db.host}:${db.porta}/${db.nome}")
}

DSLs em Kotlin são poderosas para configurações, builders de UI, definição de rotas em servidores web e muito mais. É uma das features que mais diferencia Kotlin de outras linguagens.