Why on earth, in this era of many-gigabyte machine...
# thinking-together
g
Why on earth, in this era of many-gigabyte machines, don’t all programming languages have a time-travel mode for debugging?
j
My guess? You can't take a state, and the program, and then move it one step backwards and expect to get the previous state, because the languages don't have a semantics in that direction in time. So time-travel mode would require a gazillion save files that you could reload whenever you like. And the size of the programs grows to match the available space, so programs run on many-gigabyte machines would need many-terrabyte machines to be able to record that kind of history.
g
I would be happy with something “relatively simple”: all in memory; keep a list of state value creations, always create new values rather than updating old ones, and turn off the GC.
Ideally, let me have a start-stop call so I can reverse only certain parts of the code.
Yes, you would run out of memory. But you’d use it just through some crucial set of calls and then hit a breakpoint.
k
A few years ago I built a computing stack up from machine code that I debugged by emitting a detailed log of every instruction executed and register state at every instruction -- and then browsing the resulting log in a manner akin to time travel. I spent a long time debugging all sorts of programs with this infrastructure, that requires all of a few hundred lines of code. If you care to try it out, these instructions should still work: https://github.com/akkartik/mu/blob/main/tools/browse_trace.readme.md
k
A generic time-travel debugger can be problematic because of resource requirements. So... how about a framework that lets developers add context-specific time-travelling debugging to their code, as a form of instrumentation? I have done this in Pharo Smalltalk (copying the practice of others, I didn't invent anything in this space), using the Beacon library. It implements an in-memory logging system, which in an image-based language is usually all you need in terms of logging. You can add arbitrary Smalltalk objects to your log. Including stackframes. Which you can inspect in a debugger later on (or process with your own code if that's more convenient). This isn't quite the same as time-travel because the Smalltalk image consists of mutable objects, to which stack frames only hold references. So if you have global mutable state, you have to add snapshots of it to the log as well, and then it gets messy. If you are careful with globale and/or long-lived mutable state in your overall design, which is good advice in Smalltalk anyway, it's rarely an issue in practice.
g
Hmm. My language of interest right now is Dart. They’re about to add macros. I wonder…
k
That's the idea of what @Tudor Girba calls Moldable Development : don't give developers fish but teach them fishing. Let them write their own context-dependent development tools, which are both simpler and more powerful than generic ones. Quoting Christopher Alexander ("The timeless way of building"):
So long as I build for myself, the patterns I use will be simple, and human, and full of feeling, because I understand my situation. But as soon as a few people begin to build for "the many," their patterns about what is needed become abstract; no matter how well-meaning they are, their ideas gradually get out of touch with reality, because they are not faced daily with the living examples of what the patterns say.
g
All this aside, it seems a relatively simple way to raise developer efficiency. So why isn’t something for this shipped with every language, either as a built-in feature or as a library?
k
Mindset and lack of awareness. Why implement a feature that nobody asks for, and whose utility potential clients don't even recognize when it's offered to them?
j
JetBrains has been implementing forms of speculation—if they detect a method doesn’t have side effects they’ll show the result of evaluating it before you reach it. The reaction was really positive. I don’t think they’ll bet the company on it, but I’m confident if they could implement time travel without having to switch languages/re-engineer everything they would.
w
I do not write much JavaScript, but Replay https://www.replay.io/ is a very serious attempt at an omniscient debugger. When I used it, the most remarkably helpful feature is that you could add "print statements" https://docs.replay.io/reference-guide/debugging/print-statements to an existing trace.
t
OCaml has the "time travel" debugger in ocamldebug, for programs compiled to bytecode. https://www.typeerror.org/docs/ocaml/debugger