kotlinadvanced
Builder Inference and Generic DSLs
Use @BuilderInference for type-safe DSL builders with generic type inference and collection construction.
kotlinPress ⌘/Ctrl + Shift + C to copy
// buildList with builder inference
fun main() {
// buildList — type is inferred from usage
val numbers = buildList {
add(1)
add(2)
addAll(listOf(3, 4, 5))
// Type is List<Int> — inferred
}
println("Numbers: $numbers")
// buildMap
val config = buildMap {
put("host", "localhost")
put("port", "8080")
put("debug", "true")
}
println("Config: $config")
// buildSet
val unique = buildSet {
addAll(1..5)
addAll(3..7)
}
println("Unique: $unique")
// buildString
val html = buildString {
appendLine("<!DOCTYPE html>")
appendLine("<html>")
appendLine(" <body>")
appendLine(" <h1>Hello</h1>")
appendLine(" </body>")
appendLine("</html>")
}
println(html)
// Custom builder with @BuilderInference
class Pipeline<T> {
private val steps = mutableListOf<(T) -> T>()
fun step(transform: (T) -> T) {
steps.add(transform)
}
fun execute(input: T): T =
steps.fold(input) { acc, step -> step(acc) }
}
fun <T> pipeline(block: Pipeline<T>.() -> Unit): Pipeline<T> =
Pipeline<T>().apply(block)
val stringPipeline = pipeline<String> {
step { it.trim() }
step { it.lowercase() }
step { it.replace(" ", "-") }
}
println("Pipeline: ${stringPipeline.execute(" Hello World ")}")
val intPipeline = pipeline<Int> {
step { it * 2 }
step { it + 10 }
step { it * it }
}
println("Int pipeline: ${intPipeline.execute(5)}")
// Schema builder with inference
class Schema<T> {
val fields = mutableListOf<Field<T, *>>()
fun <V> field(
name: String,
getter: (T) -> V,
validator: ((V) -> Boolean)? = null
) {
fields.add(Field(name, getter, validator))
}
fun validate(item: T): List<String> {
return fields.mapNotNull { field ->
@Suppress("UNCHECKED_CAST")
val f = field as Field<T, Any?>
val value = f.getter(item)
if (f.validator != null && !f.validator.invoke(value)) {
"${f.name}: validation failed (value=$value)"
} else null
}
}
}
data class Field<T, V>(
val name: String,
val getter: (T) -> V,
val validator: ((V) -> Boolean)?
)
fun <T> schema(block: Schema<T>.() -> Unit) = Schema<T>().apply(block)
data class Product(val name: String, val price: Double, val stock: Int)
val productSchema = schema<Product> {
field("name", { it.name }) { it.isNotBlank() }
field("price", { it.price }) { it > 0 }
field("stock", { it.stock }) { it >= 0 }
}
val valid = Product("Laptop", 999.0, 10)
val invalid = Product("", -5.0, -1)
println("\nValid: ${productSchema.validate(valid)}")
println("Invalid: ${productSchema.validate(invalid)}")
// Sequence builder
val primes = sequence {
yield(2)
var candidate = 3
val found = mutableListOf(2)
while (true) {
if (found.none { candidate % it == 0 }) {
yield(candidate)
found.add(candidate)
}
candidate += 2
}
}
println("\nFirst 15 primes: ${primes.take(15).toList()}")
// Result builder pattern
sealed class Result<out T> {
data class Ok<T>(val value: T) : Result<T>()
data class Err(val message: String) : Result<Nothing>()
}
fun <T> resultOf(block: () -> T): Result<T> = try {
Result.Ok(block())
} catch (e: Exception) {
Result.Err(e.message ?: "Unknown")
}
val r1 = resultOf { 42 / 2 }
val r2 = resultOf { 42 / 0 }
println("\nResult 1: $r1")
println("Result 2: $r2")
}Use Cases
- Type-safe collection construction
- Generic pipeline and transformation builders
- Schema validation with inferred types
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinadvanced
Type-Safe DSL Builder
Build domain-specific languages with Kotlin: receiver lambdas, @DslMarker, and nested builders.
Best for: Configuration DSLs for frameworks
#kotlin#dsl
kotlinadvanced
DSL for HTML Generation
Build a type-safe HTML DSL with Kotlin: lambda receivers, @DslMarker, and nested builders.
Best for: Type-safe template generation
#kotlin#dsl
kotlinintermediate
Type-Safe Builder for Configuration
Build configuration DSLs: server config, dependency injection setup, and nested builder patterns.
Best for: Application configuration DSLs
#kotlin#builder
kotlinadvanced
Type-Safe DSL Builder Pattern
Create type-safe DSLs in Kotlin with receiver lambdas, @DslMarker, and nested builder scopes.
Best for: HTML/XML document generation
#kotlin#dsl