liveBook · Manning

Chapter 13: DSL construction

What you will learn in chapter 13 of Kotlin in Action, 2E

Introduces Kotlin DSL design and identifies lambdas with receivers as a way to give DSL code blocks their own functions, properties, and behavior.

After this chapter you will be able to

What it builds on

Section by section

Introduction

Introduces Kotlin DSL design and identifies lambdas with receivers as a way to give DSL code blocks their own functions, properties, and behavior.

Key terms: DSL structure, lambdas with receivers, code-block-specific functions

13.1 From APIs to DSLs: Creating expressive custom code structures

This section explains why readable, maintainable code depends on clean APIs and introduces Kotlin DSLs as a way to make statically typed code more expressive.

Key terms: API, clean API, syntactic noise, DSLs, structure, method calls, statically typed, compile-time error detection, IDE support

13.1.1 Domain-specific languages

This section defines domain-specific languages, explains why their focused and declarative syntax is useful, and identifies the difficulty of combining them with general-purpose applications.

Key terms: domain-specific language, DSL, general-purpose programming language, SQL, regular expressions, declarative, imperative, execution engine, host application, string literal

13.1.2 Internal DSLs are seamlessly integrated into the rest of your program

This section contrasts external SQL with a Kotlin internal DSL, showing how a task-specific query can remain ordinary Kotlin code.

Key terms: external DSL, internal DSL, general-purpose language, Exposed, SQL, selectAll, groupBy, orderBy, native Kotlin objects

13.1.3 The structure of DSLs

This section distinguishes DSLs from ordinary APIs by the structure of their calls and explains how that structure can make code more meaningful and readable.

Key terms: DSL, command-query API, nesting of lambdas, chained method calls, grammar, internal DSL, type checker, context, infix call syntax

13.1.4 Building HTML with an internal DSL

Shows why an internal Kotlin DSL is useful for building HTML: it enforces valid tag nesting while allowing HTML to be generated with ordinary code.

Key terms: type safe, td, tr, HTML fragment, regular code, language construct, dynamically, map

13.2 Building structured APIs: Lambdas with receivers in DSLs

Introduces lambdas with receivers as a Kotlin feature for building structured DSL APIs.

Key terms: lambdas with receivers, DSLs, structure

13.2.1 Lambdas with receivers and extension function types

This section uses buildString to explain how lambdas with receivers are typed and called, then relates them to apply and with.

Key terms: lambda with a receiver, receiver, StringBuilder, buildString, extension function type, receiver type, builderAction, StringBuilder.() -> Unit, function signature, apply

13.2.2 Using lambdas with receivers in HTML builders

This section explains how lambdas with receivers give an HTML builder its structured syntax, how DSL markers limit receiver confusion, and how a simple builder constructs and renders tags.

Key terms: HTML builder, type-safe builders, lambda with a receiver, TABLE, TR, TD, implicit receiver, this@table, this@tr, this@td

13.2.3 Kotlin builders: Enabling abstraction and reuse

Shows how a Kotlin HTML builder can turn repeated page structure into reusable functions that generate both a table of contents and its content.

Key terms: internal DSLs, kotlinx.html, listWithToc, item, BODY, entries, @HtmlTagMarker

13.3 More flexible block nesting with the invoke convention

Introduces the invoke convention as a way to call custom objects like functions, while noting its selective usefulness in DSLs.

Key terms: invoke convention, function types, DSLs

13.3.1 The invoke convention: Objects callable as functions

This section explains how Kotlin’s invoke convention lets objects be called with function-call syntax and how the same convention applies to lambdas.

Key terms: invoke convention, operator modifier, invoke method, lambda, FunctionN interfaces

13.3.2 The invoke convention in DSLs: Declaring dependencies in Gradle

This section shows how Gradle-style dependency DSLs use the invoke convention to offer both flat calls and nested blocks.

Key terms: invoke method, DependencyHandler, lambda with a receiver, implicit receiver, nested block structure, flat call structure, dependencies, implementation

13.4 Kotlin DSLs in practice

Introduces upcoming practical Kotlin DSL examples involving testing, rich date literals, and database queries.

13.4.1 Chaining infix calls: The should function in test frameworks

Shows how infix calls give a statically typed testing DSL a clean, English-like assertion syntax.

Key terms: internal DSL, infix modifier, should function, Matcher, startWith, statically typed

13.4.2 Defining extensions on primitive types: Handling dates

This section explains how extension properties on Int can form a small DSL for expressing durations.

Key terms: extension properties, Int, Duration, days, hours, fortnight

13.4.3 Member extension functions: Internal DSL for SQL

This section uses Exposed’s SQL DSL to show how member extensions make column operations available only in appropriate table and query contexts.

Key terms: Exposed, Table, Column, SchemaUtils.create, member extensions, Column<Int>, autoIncrement, receiver type, select, eq

13.5 Summary

Concepts explained in this chapter

← Chapter 12: Annotations and reflection Chapter 14: Coroutines →

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.