Skip to content

Commit e8c35c3

Browse files
committed
Simpler alternative dbg!() macro
This is a simpler and more opinionated counter-proposal to [RFC 2173](rust-lang#2173).
1 parent fd70ea3 commit e8c35c3

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

text/0000-dbg-macro.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
- Feature Name: dbg_macro
2+
- Start Date: 2018-03-13
3+
- RFC PR:
4+
- Rust Issue:
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Add a `dbg!($expr)` macro to the prelude (so that it doesn’t need to be imported)
10+
that prints its argument with some metadata (source code location and stringification)
11+
before returning it.
12+
13+
This is a simpler and more opinionated counter-proposal
14+
to [RFC 2173](https://github.com/rust-lang/rfcs/pull/2173).
15+
16+
17+
# Motivation
18+
[motivation]: #motivation
19+
20+
Sometimes a debugger may not have enough Rust-specific support to introspect some data
21+
(such as calling a Rust method), or it may not be convenient to use or available at all.
22+
`printf` debugging” is possible in today’s Rust with:
23+
24+
```rust
25+
println!("{:?}", expr);
26+
```
27+
28+
This RFC improves some aspects:
29+
30+
* The `"{:?}",` part of this line is boilerplate that’s not trivial to remember
31+
or even type correctly.
32+
* If the expression to be inspected is part of a larger expression,
33+
it either needs to be duplicated (which may add side-effects or computation cost)
34+
or pulled into a `let` binding which adds to the boilerplate.
35+
* When more than one expression is printed at different places of the same program,
36+
and the formatting itself (for example a plain integer)
37+
doesn’t indicate what value is being printed,
38+
some distinguishing information may need to be added.
39+
For example: `println!("foo = {:?}", x.foo());`
40+
41+
# Guide-level explanation
42+
[guide-level-explanation]: #guide-level-explanation
43+
44+
To inspect the value of a given expression at run-time,
45+
it can be wrapped in the `dbg!` macro to print the value to `stderr`,
46+
along with its source location and source code:
47+
48+
```rust
49+
fn foo(n: usize) {
50+
if let Some(_) = dbg!(n.checked_sub(4)) {
51+
/*…*/
52+
}
53+
}
54+
55+
foo(3)
56+
```
57+
```
58+
[example.rs:2] n.checked_sub(4) = None
59+
```
60+
61+
This requires the type of the expression to implement the `std::fmt::Debug` trait.
62+
The value is returned by the macro unchanged.
63+
64+
65+
# Reference-level explanation
66+
[reference-level-explanation]: #reference-level-explanation
67+
68+
In `src/libstd/lib.rs`, `dbg` is added to the `#[macro_reexport]` attribute on `extern crate core`.
69+
70+
The macro below is added to `src/libcore/macros.rs`,
71+
with a doc-comment based on the [Guide-level explanation][guide-level-explanation] of this RFC.
72+
73+
```rust
74+
#[macro_export]
75+
macro_rules! dbg {
76+
($expr:expr) => {
77+
match $expr {
78+
expr => {
79+
eprintln!("[{}:{}] {} = {:#?}", file!(), line!(), stringify!($expr), &expr);
80+
expr
81+
}
82+
}
83+
}
84+
}
85+
86+
```
87+
88+
The use of `match` over let is similar to the implementation of `assert_eq!`.
89+
It [affects the lifetimes of temporaries](
90+
https://stackoverflow.com/questions/48732263/why-is-rusts-assert-eq-implemented-using-a-match#comment84465322_48732525).
91+
92+
# Drawbacks
93+
[drawbacks]: #drawbacks
94+
95+
Adding to the prelude should be done carefully.
96+
However a library can always define another macro with the same name and shadow this one.
97+
98+
# Alternatives
99+
[alternatives]: #alternatives
100+
101+
- See [RFC 2173](https://github.com/rust-lang/rfcs/pull/2173) and discussion there.
102+
103+
- This RFC does not offer users control over the exact output being printed.
104+
This is because a use of this macro is intended to be run a small number of times
105+
before being removed.
106+
If more control is desired (for example logging in an app shipped to end users),
107+
other options like `println!` or the `log` crate remain available.
108+
109+
- If the macro accepts more than one expression (returning a tuple),
110+
there is a question of what to do with a single expression.
111+
Returning a one-value tuple `($expr,)` is probably unexpected,
112+
but *not* doing so creates a discontinuty in the macro’s behavior as things are added.
113+
With only one expression accepted, users can still pass a tuple expression
114+
or call the macro multiple times.
115+
116+
- Printing could be disabled when `cfg!(debug_assertions)` is false to reduce runtime cost
117+
in release build.
118+
However this cost is not relevant if uses of `dbg!` are removed before shipping
119+
to any form of production (where the `log` crate might be better suited)
120+
and deemed less important than the ability to easily investigate bugs
121+
that only occur with optimizations.
122+
(Which [do happen](https://github.com/servo/servo/issues/19519)
123+
and can be a pain to debug.)
124+
125+
- Any detail of the formatting can be tweaked. For example, `{:#?}` or `{:?}`?
126+
127+
# Prior art
128+
[prior-art]: #prior-art
129+
130+
Many languages have a construct that can be as terse as `print foo`.
131+
132+
# Unresolved questions
133+
[unresolved]: #unresolved-questions
134+
135+
Unbounded bikeshedding.

0 commit comments

Comments
 (0)