Sobes.tech
Middle+

Co jsou to doménově specifické jazyky (DSL) a jak je vytvářet v Kotlinu?

sobes.tech AI

Odpověď od AI

DSL (Domain Specific Language) je malý jazyk, specializovaný pro konkrétní oblast nebo úkol, na rozdíl od jazyků všeobecného určení (GPL - General Purpose Language). Umožňuje vyjadřovat řešení problémů v termínech této oblasti, čímž činí kód čitelnějším, srozumitelnějším a výstižnějším pro odborníky v dané oblasti.

Kotlin je velmi vhodný pro tvorbu interních DSL díky podpoře funkcí, jako jsou:

  • Lambda výrazy s příjemcem: Umožňují definovat bloky kódu, které se vykonávají v kontextu určitého objektu, což usnadňuje vytváření hierarchických struktur a konfigurací.
  • Rozšiřující funkce: Umožňují přidávat nové funkce ke stávajícím třídám bez jejich modifikace, což je užitečné pro rozšíření funkcionality standardních tříd nebo knihoven třetích stran pro použití v DSL.
  • Infixové funkce: Umožňují volání funkcí bez tečky a závorek, což činí kód přirozenějším.
  • Operátory: Lze přetížit operátory (+, *, [] atd.) pro vytvoření výstižnější syntaxe.
  • Použití operátoru invoke: Umožňuje volat objekt jako funkci, což může být využito pro tvorbu stavitelů nebo konfigurátorů.
  • Typově bezpeční stavitelé (type-safe builders): Kombinace lambda s příjemcem a rozšíření, umožňující vytváření strukturovaných a typově bezpečných API.

Příklad vytvoření jednoduchého DSL pro tvorbu HTML:

import kotlinx.html.*
import kotlinx.html.stream.appendHTML
import java.io.StringWriter

fun html(block: HTML.() -> Unit): String {
    val writer = StringWriter()
    writer.appendHTML().html(block)
    return writer.toString()
}

fun body(block: BODY.() -> Unit) {
    BLOCK.BODY()(block)
}

fun p(text: String) {
    BLOCK.P() {
        +text
    }
}

Použití tohoto DSL:

fun main() {
    val result = html {
        body {
            p("Ahoj, světe!")
            p("Toto je moje první DSL.")
        }
    }
    println(result)
}

Výsledek:

<html><body><p>Ahoj, světe!</p><p>Toto je moje první DSL.</p></body></html>

Zde se lambda block: HTML.() -> Unit vykonává v kontextu objektu HTML, což umožňuje volání metod body přímo. Funkce p přidává odstavec s textem, přičemž používá přetížený unární operátor +.