
The concept of [builders|http://groovy.codehaus.org/Builders] is rather popular in the *Groovy* community. Builders allow for defining data in a semi-declarative way. Builders are good for [generating XML|http://groovy.codehaus.org/GroovyMarkup], [laying out UI components|http://groovy.codehaus.org/GroovySWT], [describing 3D scenes|http://www.artima.com/weblogs/viewpost.jsp?thread=296081] and more...
For many use cases, [Kotlin] allows to *type-check* builders, which makes them even more attractive than the dynamically-typed implementation made in *Groovy* itself.
For the rest of the cases, [Kotlin] supports [dynamic|Dynamic types] builders.
h3. A type-safe builder example
Consider the following code that is taken from [here|http://groovy.codehaus.org/Builders] and slightly adapted:
{jet}
import <ref="html_ns":>html.*
fun result(args : Array<String>) =
<ref="html":>html {
<ref="head":>head {
<ref="title":>title {<ref="plus":>+"XML encoding with Kotlin"}
}
<ref="body":>body {
<ref="h1":>h1 {<ref="plus":>+"XML encoding with Kotlin"}
<ref="p":>p {<ref="plus":>+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
<ref="a":>a(href = "http://jetbrains.com/kotlin") {<ref="plus":>+"Kotlin"}
// mixed content
<ref="p":>p {
<ref="plus":>+"This is some"
<ref="b":>b {<ref="plus":>+"mixed"}
<ref="plus":>+"text. For more see the"
<ref="a":>a(href = "http://jetbrains.com/kotlin") {<ref="plus":>+"Kotlin"}
<ref="plus":>+"project"
}
<ref="p":>p {<ref="plus":>+"some text"}
// content generated by
<ref="p":>p {
for (arg in args)
<ref="plus":>+arg
}
}
}
{jet}
This is a completely legitimate [Kotlin] code. Click on names to navigate to definitions of function used in this example (they appear below in this page).
h3. How it works
Let's walk through the mechanisms of implementing type safe builders in [Kotlin]. First of all we need to define the model we want to build, in this case we need to model HTML tags. It is easily done with a bunch of classes. For example, {{HTML}} is a class that describes the {{<html>}} tag, i.e. it defines children like {{<head>}} and {{<body>}}.
(See its declaration [below|#declarations].)
Now, let's recall why we can say something like this in the code:
{jet}
html {
// ...
}
{jet}
This is actually a function call that takes a [function literal|Function literals] as an argument (see [this page|Functions#Higher-order functions] for details). Actually, this function is defined as follows:
{jet}
fun html(init : HTML.() -> Unit) : HTML {
val html = HTML()
html.init()
return html
}
{jet}
This function takes one parameter named {{init}}, which is itself a function. Actually, it is an [extension function|Extension functions] that has a receiver of type {{HTML}} (and returns nothing interesting, i.e. [Unit|Functions#Unit]). So, when we pass a function literal to as an argument to {{html}}, it is typed as an extension function literal, and there's *this* reference available:
{jet}
html {
this.head { /* ... */ }
this.body { /* ... */ }
}
{jet}
({{head}} and {{body}} are member functions of {{HTML}}.)
Now, *this* can be omitted, as usual, and we get something that looks very much like a builder already:
{jet}
html {
head { /* ... */ }
body { /* ... */ }
}
{jet}
So, what does this call do? Let's look at the body of {{html}} function as defined above. It creates a new instance of {{HTML}}, then it initializes it by calling the function that is passed as an argument (in our example this boils down to calling {{body}} on the {{HTML}} instance), and then it returns this instance. This is exactly what a builder should do.
The {{head}} and {{body}} functions in the {{HTML}} class is defined similarly to {{html}}. The only difference is that they add the built instanced to the {{children}} collection of the enclosing {{HTML}} instance:
{jet}
fun head(init : Head.() -> Unit) {
val head = Head()
head.init()
<ref="children":>children.add(head)
return head
}
fun body(init : Body.() -> Unit) {
val body = Body()
body.init()
<ref="children":>children.add(body)
return body
}
{jet}
Actually these two functions do just the same thing, so we can have a generic version, {{initTag}}:
{jet}
protected fun initTag<T : Element>(init : T.() -> Unit) : T
where class object T : Factory<T> {
val tag = T.create()
tag.init()
<ref="children":>children.add(tag)
return tag
}
{jet}
This function uses [class objects|Classes and Inheritance#Class objects] to instantiate classes. It depends on the {{Factory}} class defined as follows:
{jet}
abstract class Factory<T> {
fun create() : T
}
{jet}
Now, the classes {{Head}} and {{Body}} declare class objects that extend {{Factory}}, for example:
{jet}
class Head() : TagWithText("head") {
class object : Factory<Head> {
override fun create() = Head()
}
// ...
}
{jet}
So, now our functions are very simple:
{jet}
fun head(init : Head.() -> Unit) = initTag(init)
fun body(init : Body.() -> Unit) = initTag(init)
{jet}
And we can use them to build {{<head>}} and {{<body>}} tags.
One other thing to be discussed here is how we add text to tag bodies. In the example above we say something like
{jet}
<ref="html":>html {
<ref="head":>head {
<ref="title":>title {<ref="plus":>+"XML encoding with Kotlin"}
}
// ...
}
{jet}
So basically, we just put a string inside a tag body, but there is this little "+" in front of it, do it is a function call that invokes a prefix "plus" operation. That operation is actually defined by an extension function {{plus}} that is a member of the {{TagWithText}} abstract class (a parent of {{Title}}):
{jet}
fun String.plus() {
<ref="children":>children.add(TextElement(this))
}
{jet}
So, what the prefix "+" does here is it wraps a string into an instance of {{TextElement}} and adds it to the {{children}} collection, so that it becomes a proper part of the tag tree.
All this is defined in a namespace {{html}} that is imported at the top of the builder example above. In the next section you can read through the full definition of this namespace.
h3. Full definition of the {{html}} namespace
This is how the namespace {{html}} is defined (only the elements used in the example above). It builds an HTML tree. It makes heavy use of [Extension functions] and [Extension function literals|Function literals#Extensions].
{anchor:declarations}{jet}
<label="html_ns":>namespace html {
<label="Factory":>abstract class Factory<T> {
fun create() : T
}
<label="Element":>abstract class Element
<label="TextElement":>class TextElement(val text : String) : Element
<label="Tag":>abstract class Tag(val name : String) : Element {
<label="children":>val children = ArrayList<Element>()