#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 Repr(value) 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 16 when None. Values <= 0 are treated as 1.

    The compact-vs-multiline layout threshold is not configurable here: render always uses the internal default of 70, keeping a node on one line when every line of its compacted form fits within that many characters.

    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\"")
    }