
body { div { a("https://kotlinlang.org") { target = ATarget.blank +"Main site" } } +"Some content" }

View from the above HTML DSL
verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } }

View from the above Android View DSL
class HelloWorld : View() { override val root = hbox { label("Hello world") { addClass(heading) } textfield { promptText = "Enter your name" } } }

View from the above TornadoFX DSL
fun Routing.api() { route("news") { get { val newsData = NewsUseCase.getAcceptedNews() call.respond(newsData) } get("propositions") { requireSecret() val newsData = NewsUseCase.getPropositions() call.respond(newsData) } } // ... }
class MyTests : StringSpec({ "length should return size of string" { "hello".length shouldBe 5 } "startsWith should test for a prefix" { "world" should startWith("wor") } })
plugins { `java-library` } dependencies { api("junit:junit:4.12") implementation("junit:junit:4.12") testImplementation("junit:junit:4.12") } configurations { implementation { resolutionStrategy.failOnVersionConflict() } } sourceSets { main { java.srcDir("src/core/java") } } java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } tasks { test { testLogging.showExceptions = true } }
filter function contains a function type to represent a predicate that decides if an element can be accepted or not.inline fun <T> Iterable<T>.filter( predicate: (T) -> Boolean ): List<T> { val list = arrayListOf<T>() for (elem in this) { if (predicate(elem)) { list.add(elem) } } return list }
-
()->Unit- Function with no arguments that returnsUnit. -
(Int)->Unit- Function that takesIntand returnsUnit. -
(Int)->Int- Function that takesIntand returnsInt. -
(Int, Int)->Int- Function that takes two arguments of typeIntand returnsInt. -
(Int)->()->Unit -Function that takesIntand returns another function. This other function has no arguments and returnsUnit. -
(()->Unit)->Unit- Function that takes another function and returnsUnit. This other function has no arguments and returnsUnit.
- Using lambda expressions
- Using anonymous functions
- Using function references
fun plus(a: Int, b: Int) = a + b
val plus1: (Int, Int) -> Int = { a, b -> a + b } val plus2: (Int, Int) -> Int = fun(a, b) = a + b val plus3: (Int, Int) -> Int = Int::plus
val plus4 = { a: Int, b: Int -> a + b } val plus5 = fun(a: Int, b: Int) = a + b
fun Int.myPlus(other: Int) = this + other
val myPlus = fun Int.(other: Int) = this + other
myPlus have? The answer is that there is a special type to represent extension functions that is called function type with a receiver. It looks similar to a normal function type, but it additionally specifies the receiver type before its arguments, and they are separated using a dot:val myPlus: Int.(Int) -> Int = fun Int.(other: Int) = this + other
this keyword references the extension receiver (an instance of type Int in this case):val myPlus: Int.(Int) -> Int = { this + it }
- Like a standard object, using the
invokemethod. - Like a non-extension function.
- Same as a normal extension function.
myPlus.invoke(1, 2) myPlus(1, 2) 1.myPlus(2)
this refers to. To see how this trait can be used, think of a class that needs to be defined property by property:class Dialog { var title: String = "" var text: String = "" fun show() { /*...*/ } } fun main() { val dialog = Dialog() dialog.title = "My dialog" dialog.text = "Some text" dialog.show() }
this, and we would be able to just skip it (because a receiver can be used implicitly):class Dialog { var title: String = "" var text: String = "" fun show() { /*...*/ } } fun main() { val dialog = Dialog() val init: Dialog.() -> Unit = { title = "My dialog" text = "Some text" } init.invoke(dialog) dialog.show() }
class Dialog { var title: String = "" var text: String = "" fun show() { /*...*/ } } fun showDialog(init: Dialog.() -> Unit) { val dialog = Dialog() init.invoke(dialog) dialog.show() } fun main() { showDialog { title = "My dialog" text = "Some text" } }
apply function that can be used instead of defining a DSL builder for setting properties.inline fun <T> T.apply(block: T.() -> Unit): T { this.block() return this } Dialog().apply { title = "My dialog" text = "Some text" }.show()
fun createTable(): TableBuilder = table { tr { for (i in 1..2) { td { +"This is column $i" } } } }
table. We are at the top-level without any receivers, so it needs to be a top-level function; however, inside its function argument you can see that we use tr. The tr function should be allowed only inside the table definition. This is why the table function argument should have a receiver with such a function. Similarly, the tr function argument needs to have a receiver that will contain a td function.fun table(init: TableBuilder.() -> Unit): TableBuilder { //... } class TableBuilder { fun tr(init: TrBuilder.() -> Unit) { /*...*/ } } class TrBuilder { fun td(init: TdBuilder.() -> Unit) { /*...*/ } } class TdBuilder
+"This is row $i"
String, and it needs to be defined inside TdBuilder:class TdBuilder { var text = "" operator fun String.unaryPlus() { text += this } }
init in the example below). Then, the builder will contain all the data specified in this init function argument. This is the data we need. Therefore, we can either return this builder, or we can produce another object that holds this data. In this example, we’ll just return the builder. This is how the table function could be defined:fun table(init: TableBuilder.() -> Unit): TableBuilder { val tableBuilder = TableBuilder() init.invoke(tableBuilder) return tableBuilder }
apply function, as shown before, to shorten this function:fun table(init: TableBuilder.() -> Unit) = TableBuilder().apply(init)
class TableBuilder { var trs = listOf<TrBuilder>() fun tr(init: TrBuilder.() -> Unit) { trs = trs + TrBuilder().apply(init) } } class TrBuilder { var tds = listOf<TdBuilder>() fun td(init: TdBuilder.() -> Unit) { tds = tds + TdBuilder().apply(init) } }
DslMarker, as explained in Item 14: Consider referencing receivers explicitly.- complicated data structures,
- hierarchical structures,
- a huge amount of data.