Does any other language have a similar feature?
Does any other language have a similar feature?
Except you often don't want a full execution, you often just want a partial execution where you suspect the problem arises. I can assure you that a good UI debugger is extremely helpful. Command line debuggers less so.
This extra work pays off pretty quickly, though. When I have a bug, I find a selection of tests that works with that code, add a couple of printf-equivalents and then rerun the tests. Usually I can spot the error in a couple of minutes. Being an older programmer (I worked professionally for over 10 years before Beck published the first XP book), I'm very comfortable with using a debugger. However since I started doing TDD, I have never once used one. It's just a lot faster to printf debug.
The way I've explained it before is that it's like having an automated debugger. The tests are just code paths that you would dig into if you were debugging. The expectations in the tests are simply watch points. You run the code and look at the results, only you don't have to single step it -- it just runs in a couple of seconds and gives you the results.
You may think that the overhead of writing tests would be higher than the amount saved with debugging and if it were only debugging, I think that would be true. However, one of the things I've found over the years is that I'm actually dramatically faster writing code with tests compared to writing it without tests (keep in mind that I've got nearly 20 years of TDD experience -- yes... I started that early on). I'm pretty good at it.
The main advantage is that when you are writing code without tests, usually you sketch together a solution and then you run the app and see if it works. Sometimes it does pretty much what you want, but usually you discover some problems. You use a debugger, or you just modify the code and see what happens. Depending on the system, you often have to get out of the context of what you are doing, re-run the app, enter a whole bunch of information, etc, etc. It takes time. Debuggers that can update information on the fly are great time savers, but you still have to do a lot of contextual work.
It takes me some extra time to write tests, but running them is super quick (as long as you aren't writing bad tests). Usually I insist that I can run the relevant tests in less than 2 seconds. Ideally I like the entire suite to run in less than a minute, though convincing my peers to adhere to these numbers is often difficult. That 2 seconds is important, though. It's the amount of time it takes your brain to notice that something is taking a long time. If it's less than 2 seconds (and run whenever you save the file), usually you will barely notice it.
In that way, I've got better focus and can stay in the zone of the code, rather than repeatedly setting up my manual testing and looking at what it is doing. Overall, it's a pretty big productivity improvement for me. YMMV.
> [src/main.rs:4] x = 5
How to differentiate the value of 'x' for a given thread/instance/whatever? Don't add the info by hand to the debug message.
edit: typo
That just means your debugger has a prohibitively high cost to use. If it takes more than 2 clicks to launch a full debugging session of your project, you need a new IDE.
With printf debugging, you can put print statements everywhere you think something might be wrong, run the program, and quickly scan through the log to see if anything doesn't match your expectations.
With print-debugging if you find a bug you have to stop your app, insert print lines, recompile, redeploy, relaunch, click through your app to reach buggy location and then scan through log. This really feels like stone-age once you've ever used a IDE.
Sometimes, print debugging is the only practical way to fix a bug. For example, very rare bugs which can only be reproduced by running many instances of the code for a long time, or situations where attaching a debugger is not feasible (as in live services).
Never used Alpine containers, so no idea how it works with DTrace / SystemTap.
However a quick web search revealed the following right away, surely there are other results available.
"Systemtap for CoreOS Container Linux"
https://medium.com/makingtuenti/systemtap-for-coreos-contain...
"App Trace Roll: Users Guide" . For Red Hat Linux clusters
https://docs.huihoo.com/rocksclusters/app-trace/4.1/index.ht...
The dbg! macro is definitely inspired by https://hackage.haskell.org/package/base-4.12.0.0/docs/Debug....
I haven't seen a debug function that returns the value again anywhere else.
https://github.com/arclanguage/anarki/blob/master/arc.arc#L1...
Edit: Yes, it's in Common Lisp too, so it goes back at least to the 1980s and probably further.
http://www.lispworks.com/documentation/HyperSpec/Body/f_wr_p...
.tap { |x| puts x }
For those of you who don't know Ruby, its map/filter/reduce functions chain like this: values.map { |x| x + 2 }.select { |x| x > 3 }
So when you want to look at an intermediate result, there's the .tap() method that runs a lambda with that intermediate result, then passes it on to the next step in the chain. [0, 1, 2, 3].map { |x| x + 2 }.tap { |x| puts x }.select { |x| x > 3 }
This returns [4, 5] after printing [2, 3, 4, 5]. ("puts" is Ruby's println.)Prints a YAML dump of "my str", followed by file/line number information, then returns its argument so it can be embedded in expressions:
$ perl -MXXX -E 'say uc(WWW("my str"))'
--- my str
...
at -e line 1
MY STR
Data::Dump's "ddx" (1996) is also commonly used for print debugging, except it doesn't return the argument. dbg!(n * factorial(n - 1))
shows up as: [src/main.rs:5] n * factorial(n - 1) = 2
[src/main.rs:5] n * factorial(n - 1) = 6
[src/main.rs:5] n * factorial(n - 1) = 24
Although, IIRC there was some crazy dumper module by dconway (who else) that worked similar to this, but I don't recall if it returned the value....
So, I just looked it up, and I found it. Actually, Damien wrote two. One that he updated from 2014 to 2016, and one he started in 2017 and has maintained to the present. I have no idea the reason for that.
Yep leave it Damien. I remember he did something similar for a test module where it would show the expressions that were evaluated in the test failure output.
With good support, a couple of trace points, even on a live running instance is all that is needed, without any extra recompiles.
More devs should learn about JTags, IntelliTrace, DTrace, ....
No need for manually writing printf-debugging and recompiling all the time, when the debugger can do that for you.
I would hope at some point you would get to the point where you move past this, once you get to Enterprise scale print debugging stuff would be slow and laborious.
Also, if I want to pause at a point and step from there, just drop `import ipdb; ipdb.set_trace()` at the line I want to set a breakpoint.