std/debug
Import with import std/debug.
Exports
Section titled “Exports”Interfaces
interface Debug
Section titled “interface Debug”interface Debug { fn inspect(value: self): String }
Protocol for producing a structural, developer-facing String
representation of a value.
Debug is the structural-representation protocol. Implementors
produce a string that “looks like the literal” — round-trippable
Nomi source for the value when feasible, or a faithful structural
rendering otherwise.
Used for developer-facing output: IO.inspect, dbg, debug logs,
and explicit Debug.inspect(value) calls. NOT used for user-facing
output — that’s Display’s job (see display.nomi). String
interpolation "${value}" calls Display, not Debug.
dbg expr is a language form, not a member of this interface. It evaluates
expr, prints the source location, source text, and Debug.inspect output,
then returns the original value. The LSP reports every dbg as a warning
because it is development-only instrumentation. IO.inspect(value) is the
ordinary module function for intentionally printing the Debug form as part
of a program’s behavior.
Debug’s function is inspect (distinct from Display.to_string) so the two
most prolific interfaces don’t collide on a function name — List.to_string
(Display) and List.inspect (Debug) read unambiguously type-qualified.
Concrete contrast for String:
Display.to_string("hello") = hello (no quotes — UI presentation) Debug.inspect("hello") = "hello" (quoted — looks like the literal)
For Int, Float, and Bool, Debug.inspect coincides with
Display.to_string because the literal source matches the user-facing form.
Debug is universal and automatic — every value is Debug.inspect-able
with no derive or explicit impl required. The compiler synthesizes a
structural Debug impl for any declared type that doesn’t supply one, so
you write an explicit impl Debug conformance only to customize a
type’s rendering.
Precedence (highest first): explicit impl Debug implementation > explicit
derive Debug > auto-synthesized structural impl.
Opaque types default to a name-only <opaque T> (a structural default
would leak exactly the internals opaque exists to hide); write an explicit
impl Debug implementation inside the type body to expose richer output. Declared
extern types default to the bare type name (True inspects as True —
internals are host-side, so there is nothing structural to render). Value
kinds with no declaration render deterministic placeholders: <function>,
<Task>, <Channel>, () (Unit), <module M>, <context>.