README

#Debug

Structural debugging and pretty-printing for MoonBit values. Provides the Debug trait, a structural representation type (Repr), and utilities for inspecting values in tests.

#Migrate from Show

We are migrating from Show to Debug for most composed values, such as arrays, maps, and tuples. Debug is designed to provide a better debugging experience: it produces structural, indented, human-readable information for data structures. The Show trait will focus on producing specialized strings, such as JSON and XML.

Breaking change: The implementations of Show::output for String and Char now produce raw text instead of quoted, escaped text.

To migrate, use Debug for test snapshots, diagnostics, and logging-style output. Some common cases:

  • Use derive(Debug) for custom types. Implement Show manually only for non-debug textual formats such as JSON, XML, or domain-specific display text.
  • Use debug_inspect(value, content=...) instead of inspect(value, content=...).
  • Use @debug.assert_eq(a, b) instead of @test.assert_eq(a, b).
  • Use \{Repr(value)} in string interpolation instead of \{value} for composed values.
  • Use @debug.to_string(value) instead of value.to_string() for composed values, when the string is only used for debugging.

#The Debug Trait

The Debug trait converts values to a structural Repr for pretty-printing. It is implemented for all primitive types, tuples (up to 22 elements), and standard collection types.

///|
test "debug" {
@debug.debug_inspect(42, content="42")
@debug.debug_inspect("hello", content="\"hello\"")
@debug.debug_inspect((1, true), content="(1, true)")
@debug.debug_inspect([1, 2, 3], content="[1, 2, 3]")
@debug.debug_inspect(Some(42), content="Some(42)")
}

#Converting to String

Use to_string to get the debug string representation of any value implementing Debug:

///|
test "to_string" {
let s = @debug.to_string([1, 2, 3])
inspect(s, content="[1, 2, 3]")
}

Use to_repr in string interpolation:

///|
test "string interpolation" {
let arr = [1, 2, 3]
inspect(
"arr: \{Repr(arr)}",
content=(
#|arr: [1, 2, 3]
),
)
}

#Printing

Use debug to print a value's debug representation to standard output:

///|
test "print" {
if false {
@debug.debug(42) // prints: 42
}
}

#Inspecting in Tests

debug_inspect compares a value's pretty-printed Repr against expected content. It raises InspectError on mismatch, making it useful for snapshot testing:

///|
test "debug_inspect" {
@debug.debug_inspect(
{ "key": 42 },
content=(
#|{ "key": 42 }
),
)
}

#Collection Support

Debug is implemented for all standard collections:

///|
test "collections" {
let q = @queue.from_array([1, 2, 3])
@debug.debug_inspect(q, content="<Queue: [1, 2, 3]>")
let dq = @deque.from_array([1, 2])
@debug.debug_inspect(dq, content="<Deque: [1, 2]>")
}

#
Debug

pub(open) trait Debug {
#as_free_fn(deprecated="Use `Repr(x)` instead")
fn to_repr(Self) -> Repr
}

Trait for types that can be converted to human-readable debugging info.
impl Debug for Unit
impl Debug for Bool
impl Debug for Byte
impl Debug for Char
impl Debug for Int
impl Debug for Int16
impl Debug for Int64
impl Debug for UInt
impl Debug for UInt16
impl Debug for UInt64
impl Debug for Float
impl Debug for Double
impl Debug for String
impl Debug for Option[T]
impl Debug for Result[T, E]
impl Debug for FixedArray[T]
impl Debug for ReadOnlyArray[T]
impl Debug for Bytes
impl Debug for ArgsLoc
impl Debug for Array[T]
impl Debug for ArrayView[T]
impl Debug for BenchError
impl Debug for Failure
impl Debug for Hasher
impl Debug for Iter[A]
impl Debug for Iter2[A, B]
impl Debug for Json
impl Debug for Map[K, V]
impl Debug for MutArrayView[T]
impl Debug for SourceLoc
impl Debug for Tuple2[A, B]
impl Debug for Tuple3[A, B, C]
impl Debug for Tuple4[A, B, C, D]
impl Debug for Tuple5[A, B, C, D, E]
impl Debug for Tuple6[A, B, C, D, E, F]
impl Debug for Tuple7[A, B, C, D, E, F, G]
impl Debug for Tuple8[A, B, C, D, E, F, G, H]
impl Debug for Tuple9[A, B, C, D, E, F, G, H, I]
impl Debug for Tuple10[A, B, C, D, E, F, G, H, I, J]
impl Debug for Tuple11[A, B, C, D, E, F, G, H, I, J, K]
impl Debug for Tuple12[A, B, C, D, E, F, G, H, I, J, K, L]
impl Debug for Tuple13[A, B, C, D, E, F, G, H, I, J, K, L, M]
impl Debug for Tuple14[A, B, C, D, E, F, G, H, I, J, K, L, M, N]
impl Debug for Tuple15[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]
impl Debug for Tuple16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]
impl Debug for Tuple17[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]
impl Debug for Tuple18[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]
impl Debug for Tuple19[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]
impl Debug for Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]
impl Debug for Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U]
impl Debug for Tuple22[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V]
impl Debug for BytesView
impl Debug for StringView

#
Repr

type Repr

Direct structural representation for debugging/diffing/pretty-printing.

impl Show for Repr
impl Debug for Repr

#
Repr::Repr

fn[T : Debug] Repr::Repr(value : T) -> Repr

Converts any value implementing Debug into a Repr.

This is the constructor of Repr, so it is written Repr(value), and it is re-exported by the prelude — no import is needed.

Parameters:

  • value : The value to convert.

Returns the Repr representation of value.

Example:

test {
inspect(Repr(42), content="42")
inspect(Repr("hello"), content="\"hello\"")
inspect(Repr([1, 2]), content="[1, 2]")
}

#
Repr::to_string

fn Repr::to_string(self : Repr) -> String

#
assert_eq

#callsite(autofill(loc))
fn[T : Eq + Debug] assert_eq(a : T, b : T, msg? : String, loc~ : SourceLoc) -> Unit raise

Assert two values are equal for debugging/tests.

This is the preferred test assertion for new code, especially for types that implement Debug but not Show.

#
debug

fn[T : Debug] debug(x : T) -> Unit

Print a value in human-readable format to standard output.

#
debug_inspect

#alias(inspect, deprecated="use `debug_inspect` without package name instead")
#callsite(autofill(args_loc, loc))
fn debug_inspect(obj : &Debug, content? : String, loc~ : SourceLoc, args_loc~ : ArgsLoc) -> Unit raise InspectError

Checks that the structural representation (Repr) of an object matches the expected content. Used in test blocks to ensure API results are as expected, and stores a pretty-printed string for comparison.

Parameters:
  • obj: The object to inspect. Must implement the Debug trait.
  • content: The expected string representation of the object. Defaults to an empty string if not provided.
  • loc: Source code location information for error reporting. Automatically provided by the compiler.
  • args_loc: Location information for function arguments in the source code. Automatically provided by the compiler.

Raises an InspectError if the actual Repr does not match the expected content.

Example:

test {
@debug.debug_inspect(42, content="42")
@debug.debug_inspect('c', content="'c'")
@debug.debug_inspect(
"hello",
content=(
#|"hello"
),
)
@debug.debug_inspect(
([1, 2, 3, 4], "string", Some(3.14)),
content=(
#|([1, 2, 3, 4], "string", Some(3.14))
),
)
}

#
dump

#deprecated("This function is for debugging only and should not be used in production")
#callsite(autofill(loc))
fn[T : Debug] dump(t : T, name? : String, loc~ : SourceLoc) -> T

Prints and returns the value of a given expression for quick and dirty debugging. This could also be useful to print some logs to trace the progress. For example, you can put dump(()) in each line, the execution will print the line number when it reaches that line.

#
render

fn render(r : Repr, max_depth? : Int) -> String

Pretty-print a Repr.

Optional parameters:
  • max_depth?: maximum expansion depth; deeper subtrees are replaced with .... Defaults to 4 when None. Values <= 0 are treated as 1.
  • compact_threshold?: compact-vs-multiline layout threshold. The printer uses a heuristic "size" for nodes; when the structure is deemed small enough under this threshold, it is kept on one line, otherwise it is broken into multiple lines. Larger values prefer single-line output. Defaults to 80 when None.

#
to_string

#alias(repr)
fn[T : Debug] to_string(x : T) -> String

Convert a value to its debug string representation. Equivalent to Repr(x).to_string(), but spelled in one step.

Also exported under the shorter name repr (re-exported from prelude, so it is callable without import). The two names refer to the same function; pick whichever reads better at the call site.

Note: this is the debug rendering, which differs from T::to_string (the Show rendering) for some types — most visibly, strings and chars are quoted and escaped here. Use @debug.to_string / repr for developer-facing output (logs, snapshots, error messages), and the Show to_string for user-facing output.

Examples

test {
let str = @debug.to_string([1, 2, 3])
@test.assert_eq(str, "[1, 2, 3]")
// Same function under a shorter name.
@test.assert_eq(repr("hi"), "\"hi\"")
}