Live data from Hacker News

What happened to proper tail calls in JavaScript? (2021)

mgmarlow.com

71–80 of 146 posts

Re: What happened to proper tail calls in JavaScript? (2021)

#71
post #68

For the most part, programming constructs like these split the world into two camps: - People who point out things can be done without them, who largely see them as useless due to lack of familiarity - People who've used them, and see critical ways to restructure code to make it cleaner using said constructs That's been the case for a lot of progress in programming. Python, and ES2015, have done a wonderful job of br…

On a tangent, I've always felt garbage collection, and, more importantly, safe memory management, was important because it allows you to mostly pretend that memory allocation isn't a globally side-effecting operation, as such operations are difficult to reason about. It's the same logic that leads to design choices that don't explicitly use global variables or global state.

In reality, all memory allocation is still globally side-effecting, and you'll find that out when your program starts GC spiraling, or consuming more memory than you want it to, but being able to pretend otherwise and mostly get away with it means automatic memory management brings a tangible, measurable productivity multiplier to programming that few, if any, other programming language features can boast of.

Re: What happened to proper tail calls in JavaScript? (2021)

#72
post #32

I use recursion in JS when implementing generic trees/dags. I'm not worried at all about growing the stack because I use the language for UI stuff, where the depth of the trees is quite shallow and the data is small overall. I don't really know what the utility of TCO/proper tail calls would be. You already have UX constraints that nudge to avoid having a ton of stuff on the screen. As an example of where recursion o…

> I don't really know what the utility of TCO/proper tail calls would be. You already have UX constraints that nudge to avoid having a ton of stuff on the screen.

The only thing you can think of using recursion for is walking the DOM?

Re: What happened to proper tail calls in JavaScript? (2021)

#73
post #49
post #43

Earlier quoted context omitted.

Javascript is also a very popular back-end language (Node JS)..

Yes, but even there it is typically used for stuff that leans towards front-end. People don't typically write databases and messaging systems in Nodejs. I wonder about specific use cases where stack allocating recursion actually becomes an issue in the JS world.

People do a lot more in JavaScript than you realize.

Re: What happened to proper tail calls in JavaScript? (2021)

#74
post #57

After thinking about this for a bit, the decision to avoid including this functionality is probably for the best. Even though I would love for this feature to exist, I can see people unintentionally shooting themselves in the foot and not understanding why. Often when you run up against call stack limitations, you actually need to reconsider the algorithm being used. Trampolines can be used to bypass the call stack l…

How can this be bad or a footgun? If the algorithm can be PTC optimized, then it is and everything works as efficiently as possible. If not, then it blows the stack either way. Finally, a trampoline is objectively worse. The programmer has to have an even bigger understanding of tail calls. Trampolines involving complex patterns are MUCH more difficult to follow. The trampoline is implemented in JS rather than C++. T…

> How can this be bad or a footgun?

You are coming from the side of someone who already has a a well planned algorithm that doesn't get stuck in infinite looping or end up diving too deep.

My concern was for those without a well planned algorithm, who don't see that it can get stuck in a loop or dives too deep too quickly. In these situations blowing your stack is a good indication you have a problem.

This is just my bias of dealing with programmers who don't do well with recursion or love to introduce function call hell.

Re: What happened to proper tail calls in JavaScript? (2021)

#75
post #68

For the most part, programming constructs like these split the world into two camps: - People who point out things can be done without them, who largely see them as useless due to lack of familiarity - People who've used them, and see critical ways to restructure code to make it cleaner using said constructs That's been the case for a lot of progress in programming. Python, and ES2015, have done a wonderful job of br…

The problem with tail calls destroying stack traces isn't with the recurse-for-the-tree functions. It's with code like this:

  function frobnicate_something(foo, bar) {
    let baz = antifrobnicate(foo, bar);
    // Hey, I'm a tail call!
    return exfoliate_meteor(baz);
  }
With tail calls, you now lose the frobnicate_something stack frame and you just see a call to exfoliate_meteor, which can produce confusing results. This lost stack frame is potentially quite injurious, especially when the function that's lost actually does a serious amount of work.

This is the rationale behind the proposal to support tail calls only on explicit scenarios, where the developer opts in to throwing away stack frames.

Re: What happened to proper tail calls in JavaScript? (2021)

#76
post #34
post #31

Earlier quoted context omitted.

You what? https://docs.python.org/3/library/functools.html?highlight=r...

No, he's right. It got 'demoted' from a core function to a footnote in a module. See also https://blog.finxter.com/about-guidos-fate-of-reduce-in-pyth...

No he's wrong. Python the language and Python the standard library are not separate things.

Re: What happened to proper tail calls in JavaScript? (2021)

#77

Earlier quoted context omitted.

Being able to guarantee tail calls is a useful optimization in far more cases than code replaceable by loops. I’ve used it myself where dispatch targets themselves are dynamic (so can’t be trivially made into a loop) for significant performance gains. Some other folks who’ve done the same thing (and can post publicly) for code that’s not just “must recurse because loops are for lowly imperative serfs”: * https://blog…

Interesting use case, didn't occur to me that tail calls can also just be a performance optimisation technique to help out the compiler and branch predictor. I assumed hot loops could be implemented just as well using GOTOs, but maybe not?

In the particular linked case of protobuf parsing, a loop with goto's doesn't produce very well optimized code because of specific internal details about how modern C compilers do optimizations. You could certainly imagine a compiler that can fully optimize a go-to heavy program, in which case the code cleanliness argument would be the only reason.

Re: What happened to proper tail calls in JavaScript? (2021)

#78
post #54

Earlier quoted context omitted.

The whole "issue" is very strange to me. Proper tail calls (PTC) without the extra syntax are literally free performance boosts for existing code. The whole "stack frames" argument is a red herring: * Nobody expects stack frames to exist for every `for` loop which is the biggest practical use for PTC * Stack frames go away the second you release control back to the event loop which is by far the more pernicious probl…

> Stack frames go away the second you release control back to the event loop which is by far the more pernicious problem. Sadly the opposite is true today: If you're doing async/await programming in Chrome (and Firefox too, I think?) the runtime actually tries to carry your stack across event loop turns and this will be visible in Error.stack. This happens even with the debugger closed in my experience (the massive s…

There are times where they are very useful.

Re: What happened to proper tail calls in JavaScript? (2021)

#79
post #68

For the most part, programming constructs like these split the world into two camps: - People who point out things can be done without them, who largely see them as useless due to lack of familiarity - People who've used them, and see critical ways to restructure code to make it cleaner using said constructs That's been the case for a lot of progress in programming. Python, and ES2015, have done a wonderful job of br…

The problem with tail calls destroying stack traces isn't with the recurse-for-the-tree functions. It's with code like this: function frobnicate_something(foo, bar) { let baz = antifrobnicate(foo, bar); // Hey, I'm a tail call! return exfoliate_meteor(baz); } With tail calls, you now lose the frobnicate_something stack frame and you just see a call to exfoliate_meteor, which can produce confusing results. This lost s…

A tail call is just a goto; using a special syntax for it (`for…` or `while…`) is simply syntactic sugar. Nobody complains about the lack of a stack frame in a for loop.

Re: What happened to proper tail calls in JavaScript? (2021)

#80
post #68

For the most part, programming constructs like these split the world into two camps: - People who point out things can be done without them, who largely see them as useless due to lack of familiarity - People who've used them, and see critical ways to restructure code to make it cleaner using said constructs That's been the case for a lot of progress in programming. Python, and ES2015, have done a wonderful job of br…

> People who point out things can be done without them, who largely see them as useless due to lack of familiarity

There's no need to dismiss the those who disagree as just having a lack of familiarity. There is a technical trade off to be made, with pros and cons each way. The only people that are objectively wrong are those that claim the decision is clear cut.

The con, in particular, is language complexity. You only have to look at C++ to see that it is possible to include to many features in a language. There's no disputing that tail calls are useful. The question is whether they are so useful that everyone who learns the language has to understand them.

Post reply on HN