Skip to content
tezvyn:

Kotlin's Type-Safe Builders: Code as Data

Source: kotlinlang.orgHardHow cards are made

Kotlin's Type-Safe Builders: Code as Data

Type-safe builders use Kotlin code to create a custom language (DSL) for building complex objects. It's like writing HTML, but the compiler validates your structure. This is common for UI layouts or server configs. The footgun is omitting @DslMarker.

Why it exists

Manually building complex, nested objects—like an HTML document tree—is verbose and error-prone. Procedural code like parent.addChild(new Child()) obscures the final structure. Type-safe builders provide a declarative, readable syntax that mirrors the object hierarchy itself, while retaining the safety of the Kotlin type system.

The mental model

Think of it as writing HTML or XML directly in your Kotlin code, but with the compiler as a strict validator. Instead of writing , you write p { ... }. The curly braces define a scope where only valid child elements can be added. You're not writing a string; you are assembling a tree of actual Kotlin objects.

How it works

The core mechanism is "function literals with receiver." A top-level function like html() accepts a lambda with a special type, HTML.() -> Unit. This means that inside the lambda's {...} block, the keyword this refers to a newly created HTML object. You can then call methods on it, like head(), without explicitly writing this.. The head() function, in turn, takes a Head.() -> Unit lambda, creating a nested scope for the <head> tag. This pattern repeats, building the entire hierarchy.

When to use it

Use builders when you need to construct complex, hierarchical data structures in a semi-declarative way. Three common use cases: first, generating markup like HTML or XML; second, configuring application components, such as defining server routes in frameworks like Ktor; third, creating structured test data in a readable format.

When not to use it

Avoid builders for simple object creation where a standard constructor or factory function is clearer and has less overhead. They are overkill if the object structure isn't hierarchical or deeply nested. The complexity of defining the builder classes only pays off for complex structures.

One canonical example

An HTML builder is the classic example. The code html { head { title { +"My Site" } } } doesn't generate a string. It calls a series of functions that instantiate and link HTML, Head, and Title objects into a tree. The crucial @DslMarker annotation prevents invalid nesting, for example, by stopping you from calling head {} from within a body {} block. The final result is a root HTML object that can then be rendered into a string.

Interview question

What is the immediate output of a successfully executed Kotlin type-safe builder block?

  • a.A hierarchical tree of interconnected Kotlin objects representing the defined structure.Correct
  • b.A set of validation rules ensuring that the generated structure adheres to specific type constraints.
  • c.A string formatted according to the builder's structure, such as HTML or XML.
  • d.A compiled DSL definition that can be reused to generate various data structures.
Why?

The card explicitly states that a builder block "doesn't generate a string" but rather "instantiate and link HTML, Head, and Title objects into a tree," with the "final result is a root HTML object." While builders are often used to eventually produce strings, their immediate output is an object hierarchy. Option C is a common misconception because builders are frequently used for markup generation.

Just read this? Test yourself on what you have been reading.

Read the original → kotlinlang.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on kotlin — each one lists the topics its interview covers.

See open roles