6 ms·
Show HN: A dbg(...) macro for C++
- pnako 7y agoIt looks pretty cool. I agree that installing the header in /usr/include is a good idea.
- the_duke 7y agoThis seems very much inspired by the `dbg` macro recently introduced in Rust. [1] Which in turn was inspired by Haskell s `Debug.Trace` functions [2]. It's definitely a convenient tool if you can't use a debugger or want to follow more complex interactions. [1]https://doc.rust-lang.org/std/macro.dbg.html https://doc.rust-lang.org/std/macro.dbg.html [2] https://hackage.haskell.org/package/base-4.12.0.0/docs/Debug-Trace.html https://hackage.haskell.org/package/base-4.12.0.0/docs/Debug...
- KenanSulayman 7y agoThanks for the Rust reference, I was hoping this exists for Rust. Very useful for everyday debugging!
- masklinn 7y ago> Which in turn was inspired by Haskell s `Debug.Trace` functions [2]. According to the RFC, the only inspiration from Debug.Trace was returning the input. The only other mention of haskell in RFCs 2173 and 2361 is the rejection of `show!`.
- the_duke 7y agoThe author of the RFC was a big Haskell user and mentioned that idea came from there. You can't learn everything from official documents...
- masklinn 7y agoThat might be true but I'd still want a source on that because the assertion makes no sense: aside from the value-returning property, all the overlap between dbg! and Debug.Trace is already covered by println!. And as far as I can see Debug.Trace doesn't contain anything like dbg!: the closest would be traceShowId, which neither shows the traced expression (before evaluation) nor the location information.
- the_duke 7y ago> but I'd still want a source on that Why don't you commence a formal inquiry, analyze the complete discussion history, acquire a sworn statement from Centril and report your findings here? It seems weird to get so hung up on the word inspired... but I'm looking forward to the report!
- deleted 7y ago[deleted]
- xtreak29 7y agoPython 3.8 has similar feature for f-strings : https://bugs.python.org/issue36817 https://bugs.python.org/issue36817 print(f"{name=}") expands to print(f"name={name}")
- chrismorgan 7y agoRust’s `dbg!()` macro also includes the source file name and line number; this C++ `dbg(…)` macro looks to add source file name, line number and function name.
- xtreak29 7y agoI proposed the idea but the debugging notation seemed to serve a different audience : https://discuss.python.org/t/filename-and-line-number-in-f-string-debugging-output/1650/ https://discuss.python.org/t/filename-and-line-number-in-f-s...
- giancarlostoro 7y agoWow I had no idea you could do that with the logging class. I agree it would be smarter to be able to at least have a flag for that to print the rest. Overall I prefer logging to print. I do think you are right though: if you are trying to debug it is useful to know the line not just a variable name. Now you gotta add garbage to say hey this was from this method and line...
- sharkdp 7y agoYes, it is definitely inspired by Rusts `dbg!(..)` macro (see bottom part of the README). A lot of my open source projects are written in Rust and I really liked the idea of the `dbg!(..)` macro, so I wanted something similar for my work in C++.
- the_duke 7y agoAh, I missed that reference at the bottom.
- solinent 7y agoDebuggers are practically useless for me, they aren't complex enough to meet my minimum use-case. If I use a debugger--approximately two hours wasted if I'm completely unaware where the problem is. If I instead try to spend ten minutes logically explaining the program, usually I fix the problem and also gain a deeper understanding of the mechanics of the program. The program is usually multi-threaded, real-time. A debugger gives you the state of the entire program, and one point in time. A log allows you to focus, which gives you the state you actually care about, at all the points in time where you care about it. The time-evolution of the state of the program is practically the only thing I'm interested in. I find that code that has been written mainly with debuggers is often full of tons of errors, often simple negations which have been worked around an even number of times. Then you're stuck with the debugger, and there's no way to reason about the program. The result is low quality.
- pcr910303 7y ago> If I use a debugger--approximately two hours wasted if I'm completely unaware where the problem is. If I instead try to spend ten minutes logically explaining the program, usually I fix the problem and also gain a deeper understanding of the mechanics of the program. Er.... I’m pretty sure debugger advocates aren’t advocating using debuggers without logical thought. Usually, it’s more about that debugger is a useful tool when one spends three hours logically explaining the problem but can’t figure it out. If you can find all kinds of bugs in ten minutes, then great! You’re officially an endorsed 10x programmer. :-) I can’t, for some bugs, (reproducing bugs in complex programs is a difficult hurdle for me too) so I use a debugger. > I find that code that has been written mainly with debuggers is often full of tons of errors, often simple negations which have been worked around an even number of times. Usually, I find that code that is thoughtfully written and extensively debugged in the debugger is the most robust part of the program, but YYMV.
- solinent 7y agoI'm not a 10x programmer, I just spend the time you spend debugging logging. And if I'm correct it's slightly less time than you spend debugging. > Usually, I find that code that is thoughtfully written and extensively debugged in the debugger is the most robust part of the program, but YYMV. Have you ever worked in a code base that is thoughtfully written but not extensively debugged? I'd wager they're pretty rare because of this extensive widespread use of debuggers, but perhaps these code bases are even more robust, since in my experience they're more thoughtfully written. Preconditions and postconditions everywhere!
- DFHippie 7y agoThe name reminds me of https://metacpan.org/pod/DBG https://metacpan.org/pod/DBG, which, full disclosure, I wrote. Not that it's nearly as cool or likely to be used by anyone, but ... it has a superficial resemblance.
- asah 7y agoWould be nice to offer runtime enable/disable. Out of curiosity, I wrote a little benchmark and submitted as a PR: https://github.com/sharkdp/dbg-macro/pull/57 https://github.com/sharkdp/dbg-macro/pull/57 The key idea is that modern CPUs dynamically branch-predict-away if-statements that are rarely/never invoked, such as a dynamically disabled dbg() call. With the performance difference magnified 10x by loop unrolling, this is what I'm seeing on my Mac laptop: 830000000 iterations in 3 secs = 2.76667e+08 iters/sec (compiled-out). 840000000 iterations in 3 secs = 2.8e+08 iters/sec (dynamically disabled). And this is the worst case, where the whole program does nothing but call dbg() - real world programs contain lots of other real work, drowning the minute difference in performance, i.e. in a real program I doubt you'd see even 0.1% total performance difference, littering it with dynamic dbg() statements. p.s. my C/C++ is pretty rusty - feedback welcome, but pls be kind.
- xiphias2 7y agoThis is not a real disabling of dbg. dbg.h should support a function that disables writing out to the screen, but still returning the expression during run-time. You could try it out with something like this: disable_dbg_output(); int a = 0; for(int i=0; i<1000000000; i++) { a += dbg(i); }
- asah 7y agoyes, correct - my code is just the performance test, which IMHO is the first step and surprisingly tricky due to effects from the loop around it. The code for dynamic enable/disable is trivial but the design is a bit subjective. For example, another API might be set_dbg_output(bool) and then maybe get_dbg_output() to inspect the current state.
- pnako 7y agoAn alternative route might be to find a way to integrate this code with a logging library like spdlog. This way you'd get the cool short notation of dbg(...) and the ability to have more control about the sinks (including indeed dynamic disabling/enabling).
- rightbyte 7y agoOh ... this is really neat. I like how you can wrap an subexpression or prettyprint vectors. When the debugger is too cumbersome to use good old prints is always a nice fallback.
- hellofunk 7y agoI wrote something similar a couple years ago, except my macro automatically compiled to a no op if compiled in release mode, which is very convenient for switching back-and-forth to the testing.
- sharkdp 7y agoThank you for the feedback. We deliberately chose not to do this (see discussion in https://github.com/sharkdp/dbg-macro/issues/26 https://github.com/sharkdp/dbg-macro/issues/26), mainly for the reasons given in the Rust documentation: > The dbg! macro works exactly the same in release builds. This is useful when debugging issues that only occur in release builds or when debugging in release mode is significantly faster. Note, however, that the C++ dbg(..) macro can be easily disabled to a no-op (identity-op, to be precise) with the DBG_MACRO_DISABLE flag.
- einpoklum 7y agoThis feels like too much of a "ricer" feature, at least the way it's implemented. Instead, you want: * A pretty-printer library (possibly single-header) * A function for obtaining the typename; see: https://stackoverflow.com/q/35941045/1593077 https://stackoverflow.com/a/56766138/1593077 for a constexpr approach. and it won't hurt to have: * A logging library with log levels (so that you don't necessarily need to recompile to enable these outputs) * A stack trace printing library When you have that, such a macro becomes nearly trivial. Oh, yeah, and - drop the silly ANSI coloring.
- stjohnswarts 7y agoHe would be a lot more receptive if you didn't use terms like "ricer" and seemingly demanding changes rather than recommending them.
- quickthrower2 7y agoWhat’s a ricer?
- Rietty 7y agoI honestly prefer the ANSI colouring. It makes it very easy to quickly differentiate different parts of the line and zone in on what is needed.
- WhiteSage 7y agoNice idea! I would appreciate a warning from the author specifying whether dbg evaluates its argument twice, as if so one must be careful with side effects when using it.
- sharkdp 7y agoThank you for the feedback. No, it does not evaluate its argument twice - see this test: https://github.com/sharkdp/dbg-macro/blob/f30cdda9fc5332e06201d886c9e6ec4b8f0f1216/tests/tests.cpp#L166-L168 https://github.com/sharkdp/dbg-macro/blob/f30cdda9fc5332e062...
- WhiteSage 7y agoThanks for the reply. Amazing work :)
- maurodelazeri 7y agoI was thinking about writing a lib like this... really useful
- 97b683f8 7y agoin lisp this would be (defmacro dbg [expr] (println '~expr ~expr))
- Ives 7y agoNot really, the C++ macro provides information about which source file the statement was generated from, as well as color coding.
- kazinator 7y ago1> (defmacro dbg (expr) (with-gensyms (val) ^(let ((,val ,expr)) (format t "~a: ~s -> ~s\n" (source-loc-str ',expr) ',expr ,val) ,val))) dbg 2> (dbg (cons 1 2)) expr-2:1: (cons 1 2) -> (1 . 2) (1 . 2) 3> (dbg (+ 2 2)) expr-3:1: (+ 2 2) -> 4 4 4> (progn (dbg (list 1 2)) (dbg (cons 1 2)) (dbg (+ 1 2))) expr-4:2: (list 1 2) -> (1 2) expr-4:3: (cons 1 2) -> (1 . 2) expr-4:4: (+ 1 2) -> 3 3 Colorization is just inserting some trivial ANSI codes. Arguably, this just slows down the program even more and increases the size of the log files. It can be done as a post-processing filter.
- israrkhan 7y agowould be nice if we had something similar for C...
- eerimoq 7y agoSee https://github.com/eerimoq/dbg-macro https://github.com/eerimoq/dbg-macro. I got inspired by this HN post and implemented it today. There's certainly room for improvment.
- bt848 7y agoThis is neat. The obvious comparison is glog's DLOG feature.
- empyrical 7y agoIt also reminds me of Qt's qDebug macros
- fabrice_d 7y agoMozilla has something similar in Gecko's codebase, inspired by the Rust macro: https://searchfox.org/mozilla-central/source/mfbt/DbgMacro.h https://searchfox.org/mozilla-central/source/mfbt/DbgMacro.h
- jedimastert 7y agoChromium's got "LOG" as well in it's debugging mode.
- rat87 7y agoI did one of these for C(or at least gcc/llvm c) but it's a lot harder to abstract over types in c so it's a bit more limited https://github.com/rtaycher/debug_print https://github.com/rtaycher/debug_print
- halfer53 7y agoIt would be great if we can see similar things in Java or golang
- s_gourichon 7y agoI wrote and use regularly similar macros in C++ context. They are less advanced on some areas, but more advanced on some. Particularly nice features: * a structured log indented by stack trace depth (fully portable, put a simple macro at function start, will log start and any exit) * log any expression: `somemacro(foo.bar())` will log `foo.bar() = 42` * log scopes like functions * with possibility to jump to source code line on one click or keypress * browse the log with structured jumps (like step into function vs advance one line, back and forth) ...just by generating a text format that is parsed by common pre-existing tools (namely emacs compilation-mode and a few other short settings). I've been planning to share that for a moment. It will eventually appear on https://github.com/fidergo-stephane-gourichon?tab=repositories https://github.com/fidergo-stephane-gourichon?tab=repositori... I wrote a similar set of macros for C, see my comment https://news.ycombinator.com/item?id=21071497 https://news.ycombinator.com/item?id=21071497 on eerimoq's "Show HN" https://news.ycombinator.com/item?id=21040649 https://news.ycombinator.com/item?id=21040649