c218d875 · core f63c1e69 · built 2026-10-26 22:39 UTCRecord Display is a runtime built-in, not Metel code
Limitation
std::core declares extend<row R> { ..R }: Display where all R: Display, so every record
whose fields are all Display is Display: anonymous and nominal records, nested records,
and records with fields whose types have a Display impl of their own. The impl's body is
not Metel code. Nothing in the language can iterate a row's fields, so the method is a
native whose host function (metel-interpreter/src/evaluator/record_display.rs,
intercepted by label in call_runtime_callable because it needs the runtime to call each
field's own to_string) formats the receiver at runtime, fields in label order:
let p := { x = 1, y = 2.5, s = "hi" };
println("${p}"); // { s: hi, x: 1, y: 2.5 }
The condition is checked statically (where all R: Display; a field without Display is
T0012 naming the field). Only the body is built in. Consequences:
- The format and the aspect are fixed in the evaluator. There is no way to write a different blanket impl, or the same impl for another aspect.
- No other aspect gets this for free.
Eq,HashandDefaultfor records, and any user aspect (a serializer, a schema generator), cannot walk a record's fields.Copyneeds no body:std::coreprovides it as an ordinary bodyless impl, so it is not affected by this limitation (metel-core#1337). - A nominal
record's ownDisplaystill wins, by brand-first dispatch (spec.types.generics.row-conditional-impls.legality-2).
Impact
Visible to Metel programmers: records print and compare through Display where they could
not before, but a user cannot write the same kind of field-walking impl for their own
aspect. Contributors: the built-in is a special case that every further derived aspect would
have to repeat in Rust.
Affects
Resolution
Planned: RFC-0174 (1-under-review, design settlement metel-core#1340) specifies a
comptime for loop over a row's fields with computed access self.[field.name], checked
once against a symbolic field. When it is implemented the std::core impl is rewritten in
Metel with that loop and record_display.rs, the label interception and the
StdCoreRecordToString native key are deleted. Until then this record stays open; the
implementation of Display itself is metel-core#1338.