# \[Pre-RFC\] Maximum depth for pretty-printed debug {:#?}

**URL:** <https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461>\
**Category:** libs\
**Created:** [December 10, 2019, 6:16am UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461 "2019-12-10T06:16:17Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![AGausmann](https://avatars.discourse-cdn.com/v4/letter/a/9de053/32.png) [@AGausmann](https://internals.rust-lang.org/u/AGausmann)\
**Post date:** [December 10, 2019, 6:16am UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/1 "2019-12-10T06:16:17Z")

</div>

Pretty-printing is great at enhancing the readability of debug output, but expanding too much can also make it hard to read.

Consider the case where I want to pretty-print an array of ordered pairs, `Vec<(usize, usize)>`. In this case, each entry will take 4 lines of output -

```rust
[
    (
        19,
        -3,
    ),
    (
        13,
        -2,
    ),
    (
        15,
        -2,
    ),
    (
        17,
        -2,
    ),
    (
        19,
        -2,
    ),
    ...
]

```

- when printing each entry on a single line would be sufficient for readability -

```rust
[
    (19, -3),
    (13, -2),
    (15, -2),
    (17, -2),
    (19, -2),
    ...
]

```

- and arguably more readable, especially for bigger lists.

What I propose to fix this is allowing the user to specify a maximum pretty-printing depth in the format string. For a max depth of `n`, only the `n`-topmost-level compound types will be expanded. In this case, the desired output can be achieved by setting a maximum depth of 1.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [December 10, 2019, 6:58am UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/2 "2019-12-10T06:58:29Z")

</div>

The formatting micro language is already quite complex. How would the alternate format depth argument be provided? Would it allow dollar-variable assignment?

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 10, 2019, 1:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/3 "2019-12-10T13:10:52Z")

</div>

The problem in general is not about depth, and can't be solved well with maximum depth.

If you had the small tuple at shallower depth, you wouldn't want it displayed in multiple lines either. Imagine a case of a tree structure where every node has one field with a small tuple (you want it compact), and other node recursing deeper into the tree (you want it multiline). There is no depth value that would print it well.

So the problem is in recursing in debug fmt and knowing which parts of the structure are going to be "small" and which are "large".

---

<div class="post-metadata">

**Author:** ![gbutler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gbutler/32/3670_2.png) [@gbutler](https://internals.rust-lang.org/u/gbutler)\
**Post date:** [December 10, 2019, 4:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/4 "2019-12-10T16:00:27Z")

</div>

> [@kornel](#):
>
> So the problem is in recursing in debug fmt and knowing which parts of the structure are going to be "small" and which are "large".

Sounds like what is needed is a way to enumerate paths to exclude/include for full expansion. Something similar to XPath or CSS selectors. I doubt though that would be a satisfactory solution.

Probably attributes on the members of structures/tuples/enums for use by the derive debug macro would work better.?

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [December 10, 2019, 4:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/5 "2019-12-10T16:41:08Z")

</div>

An approach that didn't care as much about (re) allocations could be written to take into account the size of the current node's children before formatting it, but I don't know people would be happy with us changing that to be the default. This could be solved in a more reasonable way if the formatting machinery was pluggable and replaceable by crates.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 10, 2019, 6:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/6 "2019-12-10T18:34:35Z")

</div>

Maybe this could be solved by letting `Debug` types report a heuristic length similar to `Iterator`'s `size_hint()`, but even less precise than that, so that implementations could return a fixed guesstimate without running actual formatting.

Debug output of a tuple could then ask its children how long their output may be, and based on that choose compact or multiline layout.

It will all be guesstimated, but it's a cosmetic issue, so it doesn't have to be correct every time.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [December 11, 2019, 11:40am UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/7 "2019-12-11T11:40:31Z")

</div>

That size hint should be wired to [`Arguments::estimated_capacity`](https://doc.rust-lang.org/stable/src/core/fmt/mod.rs.html#349) if it gets introduced.

---

<div class="post-metadata">

**Author:** ![derekdreery](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/derekdreery/32/2632_2.png) [@derekdreery](https://internals.rust-lang.org/u/derekdreery)\
**Post date:** [December 11, 2019, 12:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/8 "2019-12-11T12:14:16Z")

</div>

Another option is just to provide another method on Debug like `is_short`, that defaults to false. If true the pretty-printer will inline.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [December 11, 2019, 12:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/9 "2019-12-11T12:51:55Z")

</div>

`is_short` on its own doesn't really work with nesting, e.g. `(5, 6)` is short, so is `(5, (6, 7))`, but if you keep nesting two-tuples of integers you'll eventually hit something that is "not short". (Though maybe this could be tracked in the type system via specialization).

I was [recently playing around](https://github.com/Nemo157/cbor-diag-rs/commit/9ec112ed214dbb2ae0d28785acad2d9d1f0c3c6a) with a similar usecase (formatting JSON like output for user display) and ended up going with a trait like:

```rust
trait LengthEstimate {
    /// Can shortcircuit and return `max` if it is more than that
    fn estimate(&self, max: usize) -> usize;
}

```

being able to shortcircuit to avoid recursing into deeply nested types or long arrays is also useful, e.g. for an array I do:

```rust
let mut len = 4;
for item in &self {
    len += item.estimate(max - len) + 2;
    if len >= max {
        return len;
    }
}
len

```

---

<div class="post-metadata">

**Author:** ![derekdreery](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/derekdreery/32/2632_2.png) [@derekdreery](https://internals.rust-lang.org/u/derekdreery)\
**Post date:** [December 11, 2019, 2:01pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/10 "2019-12-11T14:01:20Z")

</div>

Yeah I think you are right - I just thought I'd make the `is_short` suggesting because of its simplicity.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [December 11, 2019, 2:33pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/11 "2019-12-11T14:33:18Z")

</div>

Another option to avoid runtime cost of recursion would be to make the hint a `const fn`.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [December 11, 2019, 11:38pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/12 "2019-12-11T23:38:43Z")

</div>

We don't have const trait functions yet (not even on nightly)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 10, 2020, 11:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-maximum-depth-for-pretty-printed-debug/11461/13 "2020-03-10T23:52:36Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
