Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Nice tip, I started with something short - writing a screenshot utility:

https://youtu.be/3BF-vUts3ws

Ed: i really enjoyed the video, but I feel it could have been even better (and shorter) if he used a proper debugger for the second part. But I don't know if that is available in the os.

The more I use a debugger, the more I realize I should use a debugger, and the earlier I should use a debugger.

Advice/directions to start early with a debugger might be the best part of Zed Shaws "Learn C the hard way". Eg:

https://github.com/zedshaw/learn-c-the-hard-way-lectures/blo...

(not a full featured chapter, but note that this is fairly early - exercise 4).

On a related note, it appears Shaw doesn't use the/any debugger at all in the ruby book, which is frankly quite crazy - ruby has great debuggers and repl. But that's a digression.

For a blog post that illustrate how one might do "debug driven" (or "debug first) development, see: https://nikhilism.com/post/2021/experiencing-smalltalk/

(Smalltalk and lisp does this very well - you can't AFAIK quite go that far with c++, but it's what all systems should aspire to, as a baseline (70s debug experience) ).



Debuggers are a great learning tool, but I’ve found they’re useless when diagnosing production issues. At best, you’re using C/C++ and after the crash, you get a minidump from a customer/server.

Eventually, I learned to write code that was so obviously correct and had such good error messages that I haven’t needed to use a debugger in a long time.

In fact, I don’t even know how to invoke a debugger for most languages I know.

Edit: The other good trick is to write your code so that it keeps enough state on the heap to extract useful information from core dumps. For instance, you can keep global references to lists of state that helps track issues down, and make sure they work as expected in -O3 builds. I have definitely played that game in the past.


They are only useless when the production is built with stacks that don't support stuff like Application Insights, ETW or JFR/JMX.


Reminds me of the time needed to write an application that would be particularly hard to test (was critical, handled distributed state). Managed to write it so obviously correct, that I couldn't think of anything to test before releasing the clustered version. I only ever managed to find 2 bugs, both of which were silly and unimportant.

During development, I did use REPL to run/evaluate most of the functions, on 1-2 inputs, and found a couple of silly, immediately evident bugs. Development took a couple of days, testing was about as mentioned and I really didn't want to debug.

These days, I'm amazed how people can stand to write anything at all complicated in haphazard ways, but then get to spend similar or greater time playing whack-a-mole with bugs to maybe get most of the important bugs.

Yes, good tooling can make debuggers usable. OTOH, if you need debuggers, I would consider it a shortcoming of the programming methods/structures/styles and usually even entire stacks, where debugging is practically necessary.


Debuggers aren't quite as useful with C++ indeed. But that's a good reason to use C++ less. I diagnose issues drastically faster with a debugger all the time. Often I'll write a unit test that reveals a bug, but just looking at the code doesn't quite reveal where the bug is. But sticking a few breakpoints in the right places and examining the data structures directly makes it really obvious.

Eventually, I learned to write code that was so obviously correct and had such good error messages that I haven’t needed to use a debugger in a long time.

Nobody needs to use a debugger, just like nobody needs to use most tools. They're just very helpful when they work correctly and are used correctly.


I've spent much of my career debugging C++ in rather large code bases, after inserting said bugs myself usually. If you have a set if inputs that make the problem reproducible, a debugger usually makes finding the error trivial. The only times it has taken a while is when someone (not me in this case) has done something horrible with unsafe casts, ignoring data hiding to violate a class invariant, or memcpy, or... So basically old style C. Building for release with debug info helps. Debugging with a debug build is easier sometimes, but sometimes it masks or in rare cases, creates bugs.


Andreas has made a couple of videos about why he purposefully doesn’t use a debugger (which I can’t find now) but it’s related to how he prefers to focus on a whole programs behavior and work out what’s wrong from his understanding of what it’s doing by reading the source and logs.

Incidentally Linus doesn’t use a debugger either.


Interesting. To each his own, of course - but in this one particular video, the print-debugging he does, might have been quicker and easier in a debugger (or perhaps with a core dump?). Then again, maybe not in c++.

I admit, I work mostly with ruby these days, which of course has a quite decent repl and debug experience (still whish it had full smalltalk style crash(missing method) > debugger > fix/add method > resume). Apparently someone did try that with python/rpython in the "topaz" ruby vm, but it seems abandoned. Maybe we'll get it for more languages via graal vm at some point?).


I'm used to fix and understand issues in big C++ codebases, and while eventually use a debugger, i feel that printing while passing is much better because you can see the bigger picture.

Is like putting a bell in each step so when the running bunny passes over it rings.

Later you see every place the bunny passes over and what it did, i feel its much faster to grasp and understand whats happening.

Debugging feels very slow, and i mostly use it to analyze core dumps. Also in multi-threaded/multi-process code it can change the result/output as other parts (like processes) might still run detached from the debugged thread.

Anyway, i don't like forced rules, you should use whatever works the best for you, because in the end we all have a intelligence to analyze things for our particular scenario much better than someone with a generalized point of view can.

We should always be open to learn and to see other perspectives but once we are settled we should also learn to trust ourselves and bend the "rules" when there's a need.


Multiple threads can change behavior, especially if it is a thread safety problem you are debugging. Debugging takes time mostly to reproduce the bug. If you had rr I think it might be as fast as using good logs.


That's somewhat true, it changes to me when rr works and so you can basically do print where you want and going back if you forgot something.


There's a scene in Netflix's The Queen's Gambit where two skilled Chess players are driving to New York. During the monotonous drive, they decide to play Chess. But they do so entirely verbally, no board involved as they are skilled and are able to hold the boards state within their heads.

The best way to explain how I debug is through this metaphor. I don't need the debugger to know what's happening. I know exactly what's happening with my code. The only reason I use print statements is to know what's being returned to me through other people's black boxes. I don't want to be limited to one black box query per run, so I can add multiple statements exactly where I think the black box is being weird.


I use a debugger to step into libraries and other people’s code regularly. Irrespective of whether I can or cannot hold the logic in my end I don’t find it particularly useful.

I’m not sure why a useful utility is so polarising. It’s a helpful aid - like a chisel in a carpenter’s toolbox.


> Smalltalk and lisp does this very well - you can't AFAIK quite go that far with c++, but it's what all systems should aspire to, as a baseline (70s debug experience)

Actually that was were we were going to before Java took over the stage.

"Lucid Energize Demo VHS 1993"- https://www.youtube.com/watch?v=pQQTScuApWk

https://dreamsongs.com/Cadillac.html

IBM also built on those ideas for the 4th release of Visual Age for C++.

http://www.edm2.com/0704/vacpp4/vacpp4.html

https://books.google.de/books?id=ZwHxz0UaB54C&pg=PA206&redir...


Yes. I did come across:

https://github.com/topazproject/topaz

From: "When a Mouse Eats a Python: Smalltalk-style Development for Python and Ruby" https://2017.programming-conference.org/details/MoreVMs-2017...

See also: http://www.hpi.uni-potsdam.de/hirschfeld/publications/index....

But it seems abandoned?

I guess maybe maglev ruby on the gemstone platform does move the needle a bit closer:

http://maglev.github.io/docs/persistent_code.html


> I guess maybe maglev ruby on the gemstone platform does move the needle a bit closer:

For Ruby, "pry" gets you at least some of the way there with MRI. It's nowhere near the "full experience", but it has taken a lot of inspiration from Smalltalk, and it's just an entirely different world compared to IRB.


I should clarify; I specifically meant being able to do stuff like write a high level sketch of a module, then simply run it, and implement missing methods and classes as you go. Similar to writing a red/failing test - then filling in functionality.

I suspect a image-like (as in lisp/smalltalk image) view of the code is needed for this to work well (hence the link to "persistent code" for maglev/gemstone).

That said, I do use pry/byebug a lot - but I there might very well be features I'm not aware of.


Pry does allow that with some caution. You can dip into files from the pry prompt ("edit <methodname>" opens the right file at the start of the method definition) to add methods and reload a class ("reload-code" or "reload-method"), and if you want to you can relatively easily rig things up so you're thrown into a pry prompt on method missing, implement the missing method, and reload the relevant file and retry the call.

Though I'll usually have a "boot" file that loads all pre-requisites and just call functionality from a pry prompt and edit/reload as needed rather than try to continue from a method missing or exception.


This is why many IDEs have the workspace concept, as it allows to create a metadata database with the information that would otherwise be part of the image.


Oh, there's apparently a repl for clang/c++: "cling"

http://code-ballads.net/read-eval-print-loop-repl-in-c/

https://code-ballads.net/generated-notebooks/cpp/repl_cling/...

https://github.com/root-project/cling

https://blog.jupyter.org/interactive-workflows-for-c-with-ju...

There's been some discussion on hn before, but I couldn't find anything particularly recent (or interesting tbh).

Then there is of course rr, as seen recently on hn:

"Instant replay: Debugging C and C++ programs with rr" https://news.ycombinator.com/item?id=27034588

And I also came across "inspector"- which unfortunately appears to be abandoned?

"Inspector - A drop-anywhere C++ Repl" https://news.ycombinator.com/item?id=16360738


Relevant: his youtube video on why he does not use a debugger https://www.youtube.com/watch?v=epcaK_bhWWA&t=404s


Andreas doesn’t prefer using debuggers. He’s actually touched on the subject a few times in his videos.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: