Result Builders
Result builders accumulate expressions from a content block in order and produce one strongly typed result. They apply to UI, text, and other domain objects.
Row {
Button("全部") { this.reload(null) }
Button("未完成") { this.reload(false) }
Button("已完成") { this.reload(true) }
}A parameter annotated with @BuildWith(Builder.class) must have type Function<Result()> with no parameters. The builder implements std.build.ResultBuilder<Element, Result> and offers a construction entry point callable without arguments. builders.norm defines public declarations.
Each execution of the content callback creates a separate builder. Expression statements are checked as Element and passed to add; finish is called at the end, even for an empty block. An if accumulates only its selected branch; a for accumulates in iteration order. Local declarations and assignments retain their ordinary behavior and contribute no element. Exceptions propagate at their original positions. A content block disallows return and value-bearing break.
Nested event callbacks retain ordinary function semantics. Passing an existing function value directly does not transform that function body. Builder annotations do not change separator rules for ordinary collections.
This executable example combines a result builder with field handles, lexical references, and collection results:
import std.build.BuildWith
import std.build.ResultBuilder
class Lines implements ResultBuilder<String, List<String>> {
private List<String> entries = []
Void add(String value) {
entries.add(value)
}
List<String> finish() {
return entries
}
}
List<String> report(@BuildWith(Lines.class) Function<List<String>()> content) {
return content()
}
class Task { public String title }
Void countUpdate(ref<Integer> count) {
*count = *count + 1
}
main() {
Task task = Task(title: "Draft")
FieldHandle<String> title = Task.title.field.bind(task)
Integer updates = 0
title.write("Ready")
countUpdate(count: &updates)
List<String> lines = report {
"Task: " + title.read()
if updates > 0 { "Updated ${updates} time" }
for word : ["checked", "published"] { word }
}
for line : lines { printLine(line) }
List<String> empty = report {}
printLine(empty.size())
List<String> independent = report { "Separate" }
printLine(independent[0])
}Task: Ready
Updated 1 time
checked
published
0
SeparateResultBuilderLowering provides the one frontend transformation; the compiler recognizes no particular UI component names. ResultBuilderExecutionTest covers execution, generics, diagnostics, and incremental compilation.