Bird
Raised Fist0
Kotlinprogramming~10 mins

DSL scope control with @DslMarker in Kotlin - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - DSL scope control with @DslMarker
Start DSL Builder
↓
Enter Nested DSL Scope
↓
@DslMarker Annotation
↓
Restrict Access to Outer Scope
↓
Build Inner Elements
↓
Exit Inner Scope
↓
Continue Outer Scope
↓
Complete DSL Build
The flow shows how @DslMarker annotation restricts access to outer DSL scopes when inside nested DSL blocks, helping avoid confusion and errors.
Execution Sample
Kotlin
import kotlin.annotation.DslMarker

@DslMarker
annotation class HtmlTagMarker

@HtmlTagMarker
class Html {
    fun body(init: Body.() -> Unit) { Body().init() }
}

@HtmlTagMarker
class Body {
    fun p(text: String) { println("<p>$text</p>") }
}

fun html(init: Html.() -> Unit) { Html().init() }

html {
    body {
        p("Hello")
        // Cannot access Html members here due to @DslMarker
    }
}
This code defines a simple HTML DSL with @DslMarker to prevent accessing outer Html scope inside Body block.
Execution Table
StepActionScopeAccessible MembersOutput/Result
1Call html { ... }Html scopeHtml.body()No output
2Enter body { ... } inside htmlBody scopeBody.p()No output
3Call p("Hello") inside bodyBody scopeBody.p()<p>Hello</p> printed
4Try to access Html members inside bodyBody scopeHtml members NOT accessible due to @DslMarkerCompilation error if tried
5Exit body blockBack to Html scopeHtml.body()No output
6Exit html blockEndNo members accessibleDSL build complete
💡 Execution stops after completing html block; @DslMarker prevents accessing outer scope inside nested blocks.
Variable Tracker
VariableStartAfter html callInside body blockAfter body blockFinal
Current ScopeNoneHtmlBodyHtmlNone
Accessible MembersNonebody()p()body()None
Key Moments - 2 Insights
Why can't I call Html's members inside the Body block?
Because @DslMarker annotation marks both Html and Body classes, Kotlin restricts access to outer scope members inside nested DSL blocks to avoid confusion, as shown in execution_table step 4.
What happens if I remove @DslMarker annotation?
Without @DslMarker, members from outer scopes like Html would be accessible inside Body, which can cause ambiguous calls or mistakes. The execution_table would show accessible Html members inside Body scope.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step is the p("Hello") function called?
AStep 2
BStep 3
CStep 4
DStep 5
💡 Hint
Check the 'Action' column for the call to p("Hello") in the execution_table.
According to variable_tracker, what is the current scope inside the body block?
AHtml
BNone
CBody
DBoth Html and Body
💡 Hint
Look at the 'Inside body block' column for 'Current Scope' in variable_tracker.
If @DslMarker was removed, what would change in the execution_table at step 4?
AHtml members would be accessible inside Body scope
BBody members would be inaccessible
CCompilation error would occur earlier
DNo change at all
💡 Hint
Refer to key_moments explanation about scope accessibility without @DslMarker.
Concept Snapshot
DSL scope control with @DslMarker:
- Annotate DSL classes with @DslMarker
- Restricts access to outer DSL scopes inside nested blocks
- Prevents accidental calls to wrong scope members
- Helps keep DSL code clear and safe
- Use on all related DSL classes for best effect
Full Transcript
This visual execution shows how Kotlin's @DslMarker annotation controls scope in DSLs. When you enter a nested DSL block, like Body inside Html, @DslMarker prevents you from accessing members of the outer scope (Html) inside the inner scope (Body). The execution table traces each step: starting the html block, entering body, calling p("Hello"), and shows that Html members are not accessible inside Body due to @DslMarker. The variable tracker highlights how the current scope changes from Html to Body and back. Key moments clarify why this restriction exists and what happens if you remove @DslMarker. The quiz tests understanding of scope changes and annotation effects. This helps beginners see how Kotlin keeps DSLs safe and clear by controlling scope with @DslMarker.

Practice

(1/5)
1. What is the main purpose of the @DslMarker annotation in Kotlin DSLs?
easy
A. To limit function visibility and prevent accidental calls to outer DSL scopes inside nested blocks.
B. To mark a function as deprecated in DSL usage.
C. To automatically generate DSL builder classes.
D. To enable inline functions in DSL builders.

Solution

  1. Step 1: Understand DSL nesting problem

    In nested DSL blocks, functions from outer scopes can be accidentally called inside inner blocks, causing confusion.
  2. Step 2: Role of @DslMarker

    @DslMarker annotation marks DSL builder classes to restrict visibility of outer scope functions inside nested DSL blocks, preventing accidental calls.
  3. Final Answer:

    To limit function visibility and prevent accidental calls to outer DSL scopes inside nested blocks. -> Option A
  4. Quick Check:

    @DslMarker controls scope visibility = A [OK]
Hint: Remember: @DslMarker hides outer DSL functions inside nested blocks [OK]
Common Mistakes:
  • Thinking @DslMarker generates code automatically
  • Confusing @DslMarker with deprecation annotations
  • Assuming @DslMarker enables inline functions
2. Which of the following is the correct way to define a DSL marker annotation in Kotlin?
easy
A. fun @DslMarker MyDslMarker() {}"
B. annotation class DslMarker
C. @DslMarker fun MyDslMarker() {}
D. @DslMarker annotation class MyDslMarker

Solution

  1. Step 1: Recall syntax for DSL marker annotation

    DSL marker annotations must be annotated with @DslMarker and declared as annotation classes.
  2. Step 2: Identify correct syntax

    @DslMarker annotation class MyDslMarker correctly declares an annotation class with @DslMarker annotation: @DslMarker annotation class MyDslMarker.
  3. Final Answer:

    @DslMarker annotation class MyDslMarker -> Option D
  4. Quick Check:

    DSL marker annotation syntax = A [OK]
Hint: DSL marker annotations are annotation classes with @DslMarker prefix [OK]
Common Mistakes:
  • Defining DSL marker as a function instead of annotation class
  • Missing the @DslMarker annotation on the annotation class
  • Using incorrect placement of @DslMarker keyword
3. Consider the following Kotlin DSL code snippet with two DSL marker annotations applied:
@DslMarker
annotation class FirstDsl

@DslMarker
annotation class SecondDsl

@FirstDsl
class BuilderA {
    fun a() = println("A")
    fun buildB(block: BuilderB.() -> Unit) {
        BuilderB().apply(block)
    }
}

@SecondDsl
class BuilderB {
    fun b() = println("B")
    fun buildA(block: BuilderA.() -> Unit) {
        BuilderA().apply(block)
    }
}

fun main() {
    BuilderA().apply {
        a()
        buildB {
            b()
            // Which call is allowed here?
            // a() or b() or both?
        }
    }
}
Which function call is allowed inside the buildB block?
medium
A. Only a() is allowed; b() is not visible.
B. Both a() and b() are allowed inside buildB block.
C. Only b() is allowed; a() is not visible due to DSL marker scope control.
D. Neither a() nor b() is allowed inside buildB block.

Solution

  1. Step 1: Understand effect of multiple @DslMarker annotations

    Each DSL marker annotation restricts visibility of outer scope functions from classes annotated with different DSL markers.
  2. Step 2: Analyze nested block visibility

    Inside buildB block (BuilderB scope), only b() is visible. The a() function from BuilderA is hidden due to different DSL markers.
  3. Final Answer:

    Only b() is allowed; a() is not visible due to DSL marker scope control. -> Option C
  4. Quick Check:

    Different DSL markers hide outer scope functions = C [OK]
Hint: Different DSL markers hide outer scope functions inside nested blocks [OK]
Common Mistakes:
  • Assuming all functions from outer scopes are visible
  • Ignoring effect of multiple DSL markers
  • Confusing which DSL marker applies where
4. Given the following Kotlin DSL code, what is the error and how to fix it?
@DslMarker
annotation class MyDsl

@MyDsl
class Outer {
    fun outerFun() = println("Outer")
    fun inner(block: Inner.() -> Unit) {
        Inner().apply(block)
    }
}

@MyDsl
class Inner {
    fun innerFun() = println("Inner")
}

fun main() {
    Outer().apply {
        outerFun()
        inner {
            outerFun() // Error here
            innerFun()
        }
    }
}
medium
A. Error: innerFun() is not visible; fix by removing @MyDsl annotation.
B. Error: Cannot call outerFun() inside inner block due to DSL marker scope control; fix by qualifying with this@Outer.outerFun().
C. Error: inner block is not called; fix by changing Inner().block() to Inner().apply(block).
D. No error; code runs fine.

Solution

  1. Step 1: Identify cause of error

    Inside the inner block, outerFun() is not directly visible because @MyDsl restricts access to outer scope functions.
  2. Step 2: Fix by explicit qualification

    Use explicit label this@Outer.outerFun() to call the outer function inside the inner block, bypassing DSL marker restriction.
  3. Final Answer:

    Error: Cannot call outerFun() inside inner block due to DSL marker scope control; fix by qualifying with this@Outer.outerFun(). -> Option B
  4. Quick Check:

    Use explicit this@Outer to access outer functions [OK]
Hint: Use this@Outer to call outer functions blocked by DSL marker [OK]
Common Mistakes:
  • Removing @DslMarker annotation instead of qualifying call
  • Ignoring the need for explicit receiver labels
  • Assuming innerFun() visibility causes error
5. You want to create a Kotlin DSL for building HTML-like structures with nested tags. You define two builder classes HtmlBuilder and BodyBuilder, both annotated with the same @DslMarker annotation. How does using @DslMarker help prevent mistakes when writing nested DSL code like html { body { div { ... } } }?
hard
A. It prevents calling functions from HtmlBuilder inside BodyBuilder blocks unless explicitly qualified, avoiding accidental outer scope calls.
B. It automatically generates HTML tags for each builder class.
C. It allows calling any function from HtmlBuilder inside BodyBuilder without restrictions.
D. It disables nested DSL blocks to simplify code.

Solution

  1. Step 1: Understand nested DSL structure

    In nested DSLs like HTML, inner blocks (BodyBuilder) are inside outer blocks (HtmlBuilder).
  2. Step 2: Role of @DslMarker in nested builders

    @DslMarker annotation restricts visibility of outer builder functions inside inner builder blocks, preventing accidental calls to outer scope functions without explicit qualification.
  3. Final Answer:

    It prevents calling functions from HtmlBuilder inside BodyBuilder blocks unless explicitly qualified, avoiding accidental outer scope calls. -> Option A
  4. Quick Check:

    @DslMarker hides outer builder functions inside nested blocks [OK]
Hint: Use @DslMarker to avoid accidental outer scope calls in nested DSLs [OK]
Common Mistakes:
  • Thinking @DslMarker generates code automatically
  • Assuming all functions remain visible inside nested blocks
  • Believing @DslMarker disables nesting
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard