Kotlin DSLs
Kotlin is great for writing your own Domain Specific Languages, also called type-safe builders. As you mentioned, the Anko library is an example making use of DSLs. The most important language feature you need to understand here is called "Function Literals with Receiver", which you made use of already: Test.() -> Unit
Function Literals with Receiver - Basics
Kotlin supports the concept of “function literals with receivers”. This enables calling visible methods on the receiver of the function literal in its body without any specific qualifiers. This is very similar to extension functions, in which it’s also possible to access members of the receiver object inside the extension.
A simple example, also one of the coolest functions in the Kotlin standard library, isapply
:
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
As you can see, such a function literal with receiver is taken as an argument block
here. This block
is simply executed and the receiver (which is an instance of T
) is returned. In action this looks as follows:
val text: String = StringBuilder("Hello ").apply {
append("Kotliner")
append("! ")
append("How are you doing?")
}.toString()
A StringBuilder
is used as the receiver and apply
is invoked on it. The block
, passed as an argument in {}
(lambda expression), does not need to use additional qualifiers and simply calls append
, a visible method of StringBuilder
multiple times.
Function Literals with Receiver - in DSL
If you look at this example, taken from the documentation, you see this in action:
class HTML {
fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
The html()
function expects such a function literal with receiver with HTML
as the receiver. In the function body you can see how it is used: an instance of HTML
is created and the init
is called on it.
Benefit
The caller of such an higher-order function expecting a function literal with receiver (like html()
) you can use any visible HTML
function and property without additional qualifiers (like this
e.g.), as you can see in the call:
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
Your Example
I created a simple example of what you wanted to have:
class Context {
fun onSuccess(function: OnSuccessAction.() -> Unit) {
OnSuccessAction().function();
}
class OnSuccessAction {
fun toast(s: String) {
println("I'm successful <3: $s")
}
}
}
fun temp(function: Context.() -> Unit) {
Context().function()
}
fun main(args: Array<String>) {
temp {
onSuccess {
toast("Hello")
}
}
}