Careeroza
@DslMarker
Stop Leaking Scopes
Without help, inside li { } you could still call body's p { }, because outer receivers are visible. Annotate your builders with a @DslMarker annotation and the compiler forbids implicit calls to an outer receiver.
Example
@DslMarker
annotation class MenuDsl
@MenuDsl
class Menu(val restaurant: String) {
val sections = mutableListOf<Section>()
fun section(title: String, init: Section.() -> Unit) { sections += Section(title).apply(init) }
}
@MenuDsl
class Section(val title: String) {
val dishes = mutableListOf<Pair<String, Int>>()
fun dish(name: String, price: Int) { dishes += name to price }
// section("...") { } here would NOT compile: Menu's members are hidden by @DslMarker
}
fun menu(restaurant: String, init: Menu.() -> Unit) = Menu(restaurant).apply(init)
fun main() {
val m = menu("Saravana Bhavan") {
section("Breakfast") {
dish("Idli (2)", 60)
dish("Masala Dosa", 110)
}
section("Beverages") {
dish("Filter Coffee", 40)
}
}
println(m.restaurant)
m.sections.forEach { s ->
println(" ${s.title}")
s.dishes.forEach { (n, p) -> println(" %-14s Rs %d".format(n, p)) }
}
}Output
Saravana Bhavan
Breakfast
Idli (2) Rs 60
Masala Dosa Rs 110
Beverages
Filter Coffee Rs 40