Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a shorter macro for println!("{:?}", foo) #12015

Closed
SimonSapin opened this issue Feb 3, 2014 · 29 comments
Closed

Add a shorter macro for println!("{:?}", foo) #12015

SimonSapin opened this issue Feb 3, 2014 · 29 comments
Labels
A-syntaxext Area: Syntax extensions

Comments

@SimonSapin
Copy link
Contributor

When print-debugging, I find myself writing println!("{:?}", some expression) a lot. I wish I didn’t have to write the "{:?}" part, which is always the same. For temporary debugging-only code, I don’t care about making the output pretty, I only want to see what’s going on.

So I’d like to have a new macro added wherever println!() is defined:

macro_rules! dump(
    ($a: expr) => { println!("{:?}", $a) }
    ($a: expr, $b: expr) => { println!("{:?} {:?}", $a, $b) }
    ($a: expr, $b: expr, $c: expr) => { println!("{:?} {:?} {:?}", $a, $b, $c) }
    ($a: expr, $b: expr, $c: expr, $d: expr) => { println!("{:?} {:?} {:?} {:?}", $a, $b, $c, $d) }
)

… with this pattern repeated to however many arguments is appropriate. (Although, worst case, one can always pass a tuple.) Or is there a way to write this completely generic over the number of arguments?

@sfackler
Copy link
Member

sfackler commented Feb 3, 2014

You might be able to make it generic in the number of arguments with concat!. Writing it as a procedural macro would also do it.

@alexcrichton
Copy link
Member

You can make it generic with something like:

macro_rules! dump(                                                   
    ($($a:expr),*) => {                                              
        println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }                                                                
)                                                                    

We've seen some recent pushback from including more {:?} instances in the standard library, so this may not have a great place in there (see #11793). A macro like this would be great for beginners, however.

@SimonSapin
Copy link
Contributor Author

@alexcrichton that seems mostly orthogonal. Any opinion on whether this, a macro for quick print-style debugging, is something we want at all?

@alexcrichton
Copy link
Member

I personally feel that a small debugging macro is something that'll be home-grown on a per-repo basis. The hard part right now is that macro_rules is behind a feature gate. My own personal opinion is to not include something like this in libstd, but to certainly document it in the macro tutorial or in the documentation somewhere (just as an example).

@SimonSapin
Copy link
Contributor Author

Print-style debugging IMO should be quick, ugly, and temporary. In particular, "temporary" means that I do not want debugging-only code to lie around in my code for longer than a few change/compile/test cycles. It should never end up in version control.

Given this, an example macro in the tutorial is really not that helpful, as println!("{:?}", foo) is still quicker.

This is all personal opinions of course, but anything that is not in the prelude (or equivalent) doesn’t cut it for me.

seanmonstar added a commit to seanmonstar/rust that referenced this issue Feb 19, 2014
A default format string of Poly {:?} is generated to match the number
of passed arguments. This propagates to all fmt macros, such as println!,
debug!, format!, write!, etc.

Example: println!("{:?}", value); => println!(value);

fixes rust-lang#12015
seanmonstar added a commit to seanmonstar/rust that referenced this issue Feb 20, 2014
dump! is a shorter way of quickly outputing some values to debug programs.
Example:
    dump!(val_a, 2 + 2); => "val_a = true, 2 + 2 = 4"

fixes rust-lang#12015
@dobkeratops
Copy link

nice, I have the same exact macro myself, except i add "{}:{}", file!(),line!(), ... and display the expressions eg "blah.rs:120 foo=... bar=... " etc. really handy ,as one can just click in the debug output and jump to a source location in some editors.

@reem
Copy link
Contributor

reem commented Jun 10, 2014

I was inspired by this issue to make a tiny library providing just such a macro that will also insert the file and line name, along with the expressions you are evaluating next to their results. Available here.

Example:

let a = 7;
let b = 4;
debug!(a, b, a + b);
// => file.rs - 3: a = 7, b = 4, a + b = 11

@huonw
Copy link
Member

huonw commented Jun 10, 2014

@reem that is pretty cool. I would be somewhat interested in seeing that in libdebug (although it would need a different name, to avoid conflicting with liblog's debug), I'm not sure if others agree.

@reem
Copy link
Contributor

reem commented Jun 10, 2014

How about inspect!, or perhaps dump!? I personally like inspect! a bit more, just because it sounds a bit more professional :).

@seanmonstar
Copy link
Contributor

tiny precedence: util.inspect from nodejs, though it also colorizes and pretty prints json

@reem
Copy link
Contributor

reem commented Jun 11, 2014

I'd be willing to make a PR if that's the right thing to do in this situation?

@SimonSapin
Copy link
Contributor Author

@reem, rather just than provide implementation, what’s needed now is convince the core team that this is a good idea. @alexcrichton disagrees, so far.

Personally, I think that even having to go back to the crate top-level to add extern crate debug; (assuming it’s not there permanently) whenever I want to use print-style debugging is too much overhead.

@reem
Copy link
Contributor

reem commented Jun 13, 2014

I tend to agree with you. I have started using this macro in my code for debugging and it is extremely useful, but it's pretty bothersome to have to add extern crates just to use it, then explicitly avoid checking those in to version control. Having it available by default would be great.

@SimonSapin
Copy link
Contributor Author

Given that {:?} now requires extern crate debug, I’d be in favor of just using "{}". It pushes users to implement Show on everything, but that’s probably a good thing.

@reem
Copy link
Contributor

reem commented Jun 24, 2014

@SimonSapin That's just more painful, to be honest. Now I'd like having a macro for this in the prelude even more.

@SimonSapin
Copy link
Contributor Author

To clarify: I meant having a macro in the prelude that uses expands to println!("{}", $a), println!("{} {}", $a, $b), etc.

@thestinger
Copy link
Contributor

Changes to the prelude now require a formal RFC. The {:?} formatter was moved to libdebug because it's known to be memory unsafe and will fundamentally prevent any kind of ABI stability. Adding a shortcut for it is going to be a hard sell since it's the opposite from the current direction.

@sfackler
Copy link
Member

@thestinger "memory unsafe", not safe, I'd assume :)

@thestinger
Copy link
Contributor

@sfackler: Yeah, here's one example I didn't fix when I was working on this before: #9869

I no longer have any interest in fixing the dozen remaining memory safety holes and dealing with the other breakage... and apparently no one else does, since it hasn't really been touched since then.

@SimonSapin
Copy link
Contributor Author

Given the direction {:?} is going, if I were to write an RFC for this I’d now propose generating {} instead. But I suspect that RFC would be postponed for the same reason as rust-lang/rfcs#163 was, so I won’t bother writing it just yet. If anyone else wants to, though, feel free.

@reem
Copy link
Contributor

reem commented Sep 19, 2014

I recently changed rust-inspect to use {} too.

@ftxqxd
Copy link
Contributor

ftxqxd commented Sep 19, 2014

Perhaps println!(), format!(), debug!() &c. could simply be extended to allow eliding the format string, making println!(foo, bar) equivalent to println!("{} {}", foo, bar). This has the slight disadvantage of silencing the error for println!(foo, bar) where foo is a string literal intended as a dynamic format string, and instead creating a bug at runtime. It would also be backwards-compatible, although still probably require an RFC.

@MatejLach
Copy link
Contributor

+1 for making println!(foo, bar) equivalent to println!("{} {}", foo, bar) - would make things a lot less painful.

@SimonSapin
Copy link
Contributor Author

Yes, that sounds more likely to be accepted. Anyone wants to write up an RFC?

@seanmonstar
Copy link
Contributor

I submitted a PR doing that earlier in the year, it was rejected:
#12384

@MatejLach
Copy link
Contributor

@seanmonstar Yes, this was requested a couple of times already, but for some reason it keeps getting rejected by the core team.
Maybe posting on Reddit and thus generating a wider debate on this would help?
@alexcrichton Has you opinion changed on this in any way?
Splitting this into a separate macro would defeat the purpose of this, I think.

@SimonSapin
Copy link
Contributor Author

I’ve renamed this macro show!, changed it to use {} (now that {:?} doesn’t exist anymore), and uploaded it to crates.io:

https://crates.io/crates/show
https://github.com/SimonSapin/rust-std-candidates#the-show-debugging-macro

@ivan
Copy link
Contributor

ivan commented Feb 18, 2016

I've published a crate called dump that extends the above #12015 (comment) to also print the type for each variable.

(Update: If anyone uses it, I am looking for someone to adopt the repo and crate, please email me.)

@codyps
Copy link
Contributor

codyps commented Oct 14, 2020

For those googling: dbg!() in the standard library is probably what you want

bors added a commit to rust-lang-ci/rust that referenced this issue Jul 25, 2022
[Documentation]: Update developer documentation link.

Just noticed the docs links broken. The current doc link was broken. replaced with the updated version as found on the front page. Should the rest of the links be updated?
flip1995 pushed a commit to flip1995/rust that referenced this issue Jan 11, 2024
New Lint: [`thread_local_initializer_can_be_made_const`]

Adds a new lint to suggest using `const` on `thread_local!` initializers that can be evaluated at compile time.

Impl details:

The lint relies on the expansion of `thread_local!`. For non const-labelled initializers, `thread_local!` produces a function called `__init` that lazily initializes the value. We check the function and decide whether the body can be const. If so, we lint that the initializer value can be made const.

changelog: new lint [`thread_local_initializer_can_be_made_const`]

fixes: rust-lang#12015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-syntaxext Area: Syntax extensions
Projects
None yet