This is a combination of a couple of Kotlin language features which are often used for creating DSLs, specifically:
- the invoke operator, which lets you define the
()
function call operator for a type, with an arbitrary parameter list (docs)
- being able to pass a last lambda parameter to a function outside the parantheses you usually need for the parameter list (docs)
- extensions, letting you add new methods to existing types, even if you don't own them (docs)
To achieve the syntax you've asked about specifically, you could write a method like this:
operator fun String.invoke(block: () -> Unit) {
// Do whatever you'd like with the String and the lambda
// you received as a parameter
}
The lambda you're taking as the parameter could also be an extension on any type you'd like (perhaps String
itself, but depends on your use case), could take parameters, or be expected to return a value instead of just Unit
.
The point is that inside this extension, you'll have access to the String
it was called on as this
and you'll have the lambda that was passed to it.
For further reference, here's a multi-part article that shows off some DSL building techniques.