On 09/29/2014 09:14 AM, Sam Tobin-Hochstadt wrote: > On Mon, Sep 29, 2014 at 10:55 AM, John Lenz <[email protected]> wrote: >> I really have no idea what the behavior should be in the faces of optimized >> tail calls (which is must broader than simply self recursive methods that >> can be rewritten as a loop). I've seen various suggestions (a capped call >> history) but I'm curious how efficient functional languages deal with this. > Different functional languages do a variety of things here: > > - simply show the current stack, without the functions that made tail > calls (this is probably the most common) > - have a bounded buffer for stack traces > - implement tail calls via a trampoline; this has the side-effect that > the stack has "recent" tail calls in it already > > I'm sure there are other choices here that people have made.
"Stack traces" are really an overload of (at least?) 3 different concepts: 1. A record of how execution reached the current state. What debuggers want, mostly. 2. The continuation from this point on - what function will be returned to when the current function returns normally, recursively up the call chain. 3. A description of the actual state of the stack. In all of these, the semantics of the youngest frame are different from all other frames in the stack trace. For #2, thrown exceptions make the implied continuation ordering a lie, or at least a little more nuanced. You sort of want to see what frames will catch exceptions. (But that's not a trivial determination if you have some "native" frames mixed in there, with arbitrary logic for determining whether to catch or propagate an exception. Even JS frames may re-throw.) Inlined functions may cause gaps in #1 and #2, unless the implementation takes pains to fill them in with dummy frames (in which case it's not really #3 anymore.) Unless the implementation plays games, tail calls can make #1 lie as well. You really called f(), but it doesn't appear because its frame was used for executing g() before pushing the remaining frames on your stack. Tail calls don't really muck with #2 afaict. All three meanings are legitimate things to want, and all of them require some implementation effort. Even #3 is tricky with a JIT involved. And I'm not even considering floating generator frames, which may not fit into a linear structure at all. Or when users want "long stacks" for callbacks, where the stack in effect when a callback was set is relevant. _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

