Implementing Rust's dbg! in Python(rtpg.co)
rtpg.co
Implementing Rust's dbg! in Python
https://rtpg.co/2020/12/11/dbg-in-python.html
53 comments
For anyone else wondering why we get a syntax error, this seems to be new in 3.8. :)
So anyone using Ubuntu or Debian, maybe for the next major release you can try it out. I love Debian but I hate that I cant just install the latest of Python system wide without potentially breaking system level scripts.
If you don't want to use pyenv (I think it's a mess), just look into compiling Python yourself, using a prefix like ~/.local/share/python-$version
Just use pyenv (careful with spelling), then you can use any version you like.
Definitely will have to check it out with two endorsements, I've heard of a few other options, but this might be something I'm actually okay with.
System Python is for the system, leave it alone. Use https://github.com/pyenv/pyenv and get every Python you want in seconds for your personal use.
[deleted]
I use icecream [1] for the same purpose while debugging. It's really handy.
[1] https://github.com/gruns/icecream
[1] https://github.com/gruns/icecream
Thanks for sharing! I like that ic includes a hook for logging, which I think is an advantage over calling print directly. I realize for a lot of examples, they’re quick and dirty but I almost always end up setting up a logger with an stderr or stdout handler so that other handlers can also send it to a file if desired. This makes it easier to run these in production on daemons and such where your code might not have an stdout to print to.
Title should definitely have `dbg!` in it rather than "Dbg"
Probably was submitted with the correct title and then rewritten by the HN title modification ruleset.
I think submitters are able to correct the title for a while and that when they do it might(?) override some or all of the rules in the filter. But the time window for doing so has probably been passed now.
Mods could still change the title though.
Either to the original:
Implementing Rust's dbg! in Python
Or if they want to help out those unfamiliar with Rust syntax they might make the title be:
Implementing Rust's dbg! macro in Python
And if they are opposed to use the bang even in this context it would then be fine IMO to either preferably set the title to:
Implementing Rust's dbg macro in Python
Or less preferably to set the title to:
Implementing Rust's debug macro in Python
I think submitters are able to correct the title for a while and that when they do it might(?) override some or all of the rules in the filter. But the time window for doing so has probably been passed now.
Mods could still change the title though.
Either to the original:
Implementing Rust's dbg! in Python
Or if they want to help out those unfamiliar with Rust syntax they might make the title be:
Implementing Rust's dbg! macro in Python
And if they are opposed to use the bang even in this context it would then be fine IMO to either preferably set the title to:
Implementing Rust's dbg macro in Python
Or less preferably to set the title to:
Implementing Rust's debug macro in Python
@dang we are in great need
Fixed now.
Rust's dbg! is one of those ideas that felt obvious and beautiful once I saw it.
Apparently it's inspired by Haskell.[0] I'd love to see it officially picked up in other languages.
[0] https://rust-lang.github.io/rfcs/2361-dbg-macro.html#prior-a...
Apparently it's inspired by Haskell.[0] I'd love to see it officially picked up in other languages.
[0] https://rust-lang.github.io/rfcs/2361-dbg-macro.html#prior-a...
I've been using it in C/C++ projects going back at least 15 years, I thought it was commonplace for every language
Do you have an example of using it in C or C++?
There's a few significant differences here. This is a printf that only happens in debug mode; dbg is something that takes an expression, returns that expression, and will print out its filename, line number, and a pretty-printed version of the value.
For an example of how this plays out, I had some code:
Basically, what you posted is in the same genre of thing, but is very different in a lot of meaningful ways.
For an example of how this plays out, I had some code:
let x = y + z;
I wasn't sure what y was, so I was able to let x = dbg!(y) + z;
this is much easier to insert into (and remove from) existing code. Plus, you don't need to write the formatting code.Basically, what you posted is in the same genre of thing, but is very different in a lot of meaningful ways.
After I saw this in Rust, I had to implement it in C++:
#include <iostream>
#include <string>
template<typename T>
T print_dbg(T val, std::string exp, std::string file, int line)
{
std::cerr << exp << " = " << val << " @ " << file << ":" << line << "\n";
return val;
}
#define dbg(x) print_dbg(x,#x,__FILE__,__LINE__)Close. Applying that to
If I could I would probably want to write
double c = dbg(dbg(a) + dbg(b));
gives a = 1 @ debug.cxx:16
b = 2 @ debug.cxx:16
dbg(a) + dbg(b) = 3 @ debug.cxx:16
which has extra dbg()s on the third line.If I could I would probably want to write
double dbg(c) = dbg(a) + dbg(b);
but that of course doesn't work.You can use dbg inline within an expression!? How did I miss that?
You can even use it inside itself. I've written
let c = dbg!(dbg!(a) + dbg!(b));
one time...Like Steve said, what you're talking about is quite a bit different than what the rust dbg macro does.
It isn't really that different, it can just be used in inline expressions. Having the macro do nothing or just evaluating to the expression in debug mode is trivial, since a debug symbol would be defined.
[deleted]
Here's a lib with similar functionality: https://github.com/alexmojaki/snoop
Might be worth mentioning that you do not have to resort to printf debugging in Rust or python; both languages have good ide debugger support. I use python and rust together professionally.
printf debugging (i.e. listing code execution traces) is better than a breakpoint-based debugger in most situations, in my opinion.
For what it's worth, I made a Python package that lets you combine both approaches: https://github.com/breuleux/breakword. You run your program once to print out what's going on, but it also displays a unique word next to each line and on a second run you can set a breakpoint at any of these words to investigate deeper. It's pretty handy when you spot an issue at the hundredth invocation of some function deep in the program's execution.
That's really awesome.
For something quick, it's often more ergonomic to just print a thing out than step through. Also, most debuggers also won't be very helpful for embedded expressions; you have to break it out into a local variable.
You can set a breakpoint and also watch expressions, so there is not more work involved than hitting 2 keyboard shortcuts usually.
[deleted]
They do, but sometimes you have to debug in an environment where an IDE is not available, and even remote attach can be problematic sometimes.
And then, sometimes, you need to debug the debugger...
And then, sometimes, you need to debug the debugger...
Would this make sense in a logging situation?
The one thing I wasn't sure that I liked with rust's dbg! is that I was typically passing the argument by value, but that sometimes works and sometimes fails the borrow checker. But now reading https://github.com/rust-lang/rust/issues/59943 I see that this is a feature -- I hadn't been taking advantage of the fact that you can use dbg! inline; I'd just been adding extra dbg!(foo) lines to the code. So I should probably (a) pass by reference always and (b) look our for where inline dbg! might be useful (probably lots).
I created a similar macro in C++, it had the ability to show the function name in addition to the file name
But did it return the value being printed? That's the thing most implementations miss.
Oh never thought about that use case but I imagine it would have been simple to add
I dont get, isn't this just grabbing the filename (which has a built-in double underscore file variable), and the line number (e.g. https://code.activestate.com/recipes/145297-grabbing-the-cur...)
not to mention you can run via pdb and display or stop at points of interest.
what am I missing?
not to mention you can run via pdb and display or stop at points of interest.
what am I missing?
dbg! also prints out both the value of the expression, and the expression itself, so dbg!(x+y) prints 'x+y=3'
Typo in your first eval example:
>>> foo = {
... 'bar': 3
... }
>>> print(eval("foo['bar'[]"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
foo['bar'[]
^
SyntaxError: unexpected EOF while parsingMy personal experience is that doing println/dbg based debugging in python is most times a bad idea and does wast time.
Ironically my experience with rust is the opposite, i.e. not using println/dbg debugging is most times does wast time. (Except if you do certain thinks with unsafe code).
The difference is I guess that in rust I normally encode much more simple invariant in the type system and as such most times a bug happens I often can pin-down it's rough position by the way it appears (i.e. panics/errors not subtle timing bugs). In turn I just need to get a nice formatted printout of this one or two values. Instead of having to consider all the other ways things might have cone wrong in python which can't happen in rust (through python3's type annotation + linting can help).
Ironically my experience with rust is the opposite, i.e. not using println/dbg debugging is most times does wast time. (Except if you do certain thinks with unsafe code).
The difference is I guess that in rust I normally encode much more simple invariant in the type system and as such most times a bug happens I often can pin-down it's rough position by the way it appears (i.e. panics/errors not subtle timing bugs). In turn I just need to get a nice formatted printout of this one or two values. Instead of having to consider all the other ways things might have cone wrong in python which can't happen in rust (through python3's type annotation + linting can help).
You don't need IPython for startup scripts... https://docs.python.org/3/library/site.html
Another somewhat similar Python library, but logs to a /tmp file: https://github.com/zestyping/q
In [8]: print(f'{foo.bar[1]=}') foo.bar[1]='2'
You can do more complex expressions:
In [9]: f'{1+1=}' Out[9]: '1+1=2'
It's not quite as fluid as dbg!(), but it's nice.