Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to hide variables from lambda's closure?

I'm trying to crate a type-safe groovy-style builder in Kotlin like it's described here. The problem is visibility of lambda receivers in nested lambdas. Here is a simple example.

html {
    head(id = "head1")
    body() {
        head(id = "head2")
    }
}

Receiver of the nested lambda is Body that doesn't have the 'head' method. Nevertheless this code compiles and prints into this:

<html>
    <head id="head1"></head>
    <head id="head2"></head>
    <body></body>
</html>

It is expected but is there any way to get compilation error on the inner head?

like image 877
Alexey Pomelov Avatar asked Sep 12 '16 18:09

Alexey Pomelov


2 Answers

As of Kotlin 1.0 this is not possible. There is an open feature request for this functionality.

like image 167
yole Avatar answered Sep 22 '22 02:09

yole


This is possible since Kotlin 1.1, thanks to the introduction of the @DslMarker annotation.

Here's an example of how it can be used:

@DslMarker
annotation class MyHtmlDsl

@MyHtmlDsl
class HeadBuilder

@MyHtmlDsl
class BodyBuilder

@MyHtmlDsl
class HtmlBuilder {
    fun head(setup: HeadBuilder.() -> Unit) {}
    fun body(setup: BodyBuilder.() -> Unit) {}
}

fun html(setup: HtmlBuilder.() -> Unit) {}

fun main(args: Array<String>) {
    html {
        head {}
        body {
            head { } // fun head(...) can't be called in this context by implicit receiver
        }
    }
}

See also the documentation at the announcement linked above.

like image 26
zsmb13 Avatar answered Sep 23 '22 02:09

zsmb13