Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Kotlin's type safe builders to work in Scala?

Kotlin has awesome type safe builders that make possible to create dsl's like this

html {
  head {
    title("The title")
    body {} // compile error
  }
  body {} // fine
}

Awesomeness is that you cannot put tags in invalid places, like body inside head, auto-completion also works properly.

I'm interested if this can be achieved in Scala. How to get it?

like image 747
Yaroslav Avatar asked Sep 22 '16 06:09

Yaroslav


People also ask

What is type-safe builder?

Type-safe builders allow creating Kotlin-based domain-specific languages (DSLs) suitable for building complex hierarchical data structures in a semi-declarative way. Sample use cases for the builders are: Generating markup with Kotlin code, such as HTML or XML. Configuring routes for a web server: Ktor.

How do I build DSL in Kotlin?

To make a DSL means to change the syntax of that specific part of the code. In Kotlin, this is achieved by using lambda and extension functions, and expressions, to remove a lot of boilerplate code and hide the internal implementation from the user.

Is Kotlin type-safe?

In the Kotlin world, we call them type-safe builders. Type-safe because all functions and values have types, and so the compiler can validate your writings.


1 Answers

If you are interested in building html, then there is a library scalatags that uses similar concept. Achieving this kind of builders does not need any specific language constructs. Here is an example:

object HtmlBuilder extends App {
    import html._
    val result = html {
        div {
            div{
                a(href = "http://stackoverflow.com")
            }
        }
    }
}

sealed trait Node
case class Element(name: String, attrs: Map[String, String], body: Node) extends Node
case class Text(content: String) extends Node
case object Empty extends Node

object html {
    implicit val node: Node = Empty
    def apply(body: Node) = body
    def a(href: String)(implicit body: Node) =
        Element("a", Map("href" -> href), body)
    def div(body: Node) =
        Element("div", Map.empty, body)
}

object Node {
    implicit def strToText(str: String): Text = Text(str)
}
like image 55
Yevhenii Melnyk Avatar answered Oct 14 '22 13:10

Yevhenii Melnyk