Narrowing Access with Scope Control
We'll cover the following
You’ve seen how to create internal DSLs in Kotlin. Unlike external DSLs, internal DSLs have the benefit of riding on a host language, and we don’t have to implement parsers. That removes a lot of effort on our part as DSL designers. However, anything that’s possible in the host language, like property access or calls to arbitrary functions and methods in scope are all permitted within the DSL code. That freedom may be too much at times. Kotlin makes an effort to narrow that access a little with a scope control annotation.
Narrowing access
In spite of the facility Kotlin offers, there’s no way to tell the compiler to reject calls to a top-level function or an access to a variable that’s in lexical scope. But, with a special @DSLMarker
annotation, you can tell the compiler to disallow implicit access to the members within the parent receiver of a nested lambda.
We discussed in Multiple Scopes with Receivers, how nested lambdas have two receivers, one that’s the this
context object of the executing lambda and the other that’s the receiver of the parent lambda. When creating a DSL, we may want to limit a lambda to accessing only the immediate implicit receiver and disallow automatic access to the members of the parent receiver. Let’s take a look at an example where placing that limitation will be useful.
Let’s modify the code we created previously to create the XML output for languages and authors. Previously we nested a call to element()
within another element()
to create a child element. But what if we add a call to root()
inside the lambda passed to element()
, like so:
Get hands-on with 1200+ tech skills courses.