6 ms·
> One observable consequence of tail calls is (besides a reduced risk of stack overflow) that tail callers do not appear in stack traces. Neither do they appear
by skybrian 4y ago
> One observable consequence of tail calls is (besides a reduced risk of stack overflow) that tail callers do not appear in stack traces. Neither do they appear in the stack property of a caught exception, nor in the DevTools stack trace. By the time an exception is thrown, or execution pauses, the tail caller frames are gone and there is no way for V8 to recover them.
It seems like a compiler could unroll a function one step, so the first internal call isn't a tail call? Then the first stack frame with the initial arguments would remain on the stack, and the stack trace would be similar to what it would be if you wrote a loop instead.
- Rusky 4y agoSometimes it's not just a single function calling itself, but a whole bunch of functions calling into each other, which can get more confusing. This is also tricky when you have indirect tail calls, because now you don't know if it's the first call to that particular function so you can't always unroll it anyway.
- skybrian 4y agoI'm thinking of something like an interpreter, where each function implements one instruction and it does tail calls to go to the next instruction, instead of having a giant switch statement in a loop. To match the implementation without tail calls, you probably don't want the previous instruction(s) on the stack, but all entry points into the interpreter should probably be on the stack.
- Rusky 4y agoYou can get this without the compiler doing any unrolling, by doing non-tail calls at the points where you enter the interpreter.
- cryptonector 4y agoThis is really not a problem.
- tokamak-teapot 4y agoIt really is. I often have to go and modify some (tail-call-optimised-away) code just to get it to turn up in a stack trace so that I can continue with what I’m debugging.
- parasti 4y agoWhy debug optimized code?
- kvdveer 4y agoBecause that's the code that throws the exceptions after the product has left the lab.
- duped 4y agoIt's no worse than a do-while loop.
- cryptonector 4y agoJust yesterday I had to reason about a stack trace involving tail calls. I worked it out. I wouldn't rather lose TCO so I could get stack traces that I don't have to reason about.
- chriswarbo 4y ago> One observable consequence of tail calls is (besides a reduced risk of stack overflow) that tail callers do not appear in stack traces. Neither do they appear in the stack property of a caught exception, nor in the DevTools stack trace. This is because stack traces are continuations; i.e. they show the future of our computation; those things which have not yet been done. Reaching a function's tail position means, by definition, that its computations are finished. Hence why such functions don't appear in stack traces; the same way that, say, a call like 'foo(bar(42))' won't include 'bar' in a stack trace if 'foo' crashes. > By the time an exception is thrown, or execution pauses, the tail caller frames are gone and there is no way for V8 to recover them. This can be done by a time-travelling debugger; since that keeps a trace of past computations. It also adds overhead, though.
- mike_hock 4y agoEveryone: We want mandatory tail call elimination. Also everyone: We want complete stack traces. Imagine wanting O(call depth) stack frames after demanding that the stack can only use O(1) memory.
- d33 4y agoOne thing that I wonder about is: could we write extra code that makes those reversible? I understand that there are no stack frames other than the topmost one, but maybe if we recorded the first and last one as well as a copy of the arguments, it could be enough to reconstruct the flow?
- deleted 4y ago[deleted]