We’ll never know how big of a role TCO could have played in JavaScript over the past several years, because it hasn’t been available outside of some narrow contexts.
We’ll never know how big of a role TCO could have played in JavaScript over the past several years, because it hasn’t been available outside of some narrow contexts.
Where recursion is clearer (for example, when dealing with recursively nested data structures), the clearest expression of a function usually isn't tail recursive - that often requires rewriting the function to put more state into the function arguments.
This means that tail recursion rarely matches with patterns used regularly in Javascript. That's not to say it's useless - if you want to keep to a particular functional style, or if you're compiling to Javascript from a language that emphasises recursion, then it's a useful tool to have. But in the former case, you're generally going to struggle with browser engines not being optimised for this style, and in the latest case, you're probably better off targeting WASM directly.
There’s an element in this that gets at why V8’s omission of TCO feels to me like suppression of functional programming. JavaScript is an incredible widely used multi-paradigm language, to the point that I would recommend for universities to replace Python and Java with JavaScript in their curriculums. It’s just so practical for building software systems, has amazing tooling, connects you to a rich community, and allows you to cover so much academic ground. JavaScript has been a rocket fuel for promoting a vibrant, diverse software engineering ecosystem.
Although you can choose to write a loop and do things imperatively in JavaScript, you don’t have to. The ECMAScript spec is inclusive toward the functional programming paradigm by requiring that engines provide for proper tail calls. Functional programmers should be allowed to have their cake and eat it too! But TCO isn’t implemented in V8, and the workaround is to just switch from functional to imperative programming.
You can mimic all of that, but it's painful, it's not something that Javascript is that great at. Which is fair enough, it doesn't need to be perfect at everything, that's why there's different languages. If you want functional programming in the browser, try using Elm or ReasonML. Both of those are fairly easy to use, I think there are even online playgrounds for both to get started.
const times = a => b => a * b
const double = times(2)
const twiceFour = double(4)
As a language feature, a function to curry a given function is different from proper tail calls in that it can be implemented as a JavaScript function rather than needing to be built into the JavaScript engine. Similarly, Haskell’s own curry function is imported from its standard prelude. Leaving this detail up to language users allows a diversity of approaches and vibrancy in the community. Lodash has had an implementation for a while: https://github.com/lodash/lodash/blob/0843bd46ef805dd03c0c8d.... (Edit, found better example.)Structural pattern matching can be very elegant and it would be nice if ECMAScript offered it. Object destructuring has been added to the language, and that feature could be seen as a stepping stone for adding structural pattern matching in a later version. Proper tail calls however are more fundamental to the paradigm of functional programming, since they are necessary for iterative algorithms to work as well functionally as they do imperatively.
In Javascript, a function that accepts two arguments is meaningfully different from a function that accepts one argument and returns a new function that accepts a second argument. Both semantically, but more importantly syntactically. It's possible to overcome this at the library level as you say, but it usually has performance and usability issues - error messages start looking very funky! It also often doesn't play well with other Javascript features, such as the famous `map(parseInt)` issue.
That's not to say that currying isn't possible in Javascript, just that it's a feature that doesn't play well with the rest of Javascript. If you really want currying when you're coding, you're probably better off choosing another language - currying will work so much better, and you will have so many more advantages.
What I've said is specific to currying, but in my experience, this is generally true. You can use certain functional idioms in Javascript (particularly higher order functions), but it isn't really a functional programming language. Adding features to make Javascript more functional makes the language a lot more complex, but it won't magically turn Javascript into a good functional language. Therefore, it doesn't make sense to include things in Javascript just because they're useful in a functional context, it's first important to validate that these features are useful in a standard Javascript context.
They have a stage 2 record/tuple proposal. Records are far more optimizable than JS classes since they enforce concrete types and can’t add/remove fields.
Instead, they spent massive amounts of time on private fields which most devs didn’t want (most pushback any JS feature has ever received by a large margin) AND one that completely breaks proxies which are used by all kinds of libraries.
Even Java is getting pattern matching before JS.
They’ve decided pipe operators are either going to be an abomination or they will be cancelled entirely. So of this completely disregards the opinions and use cases of the FO devs that will be using them.
This applies to all the FP proposals on their list. They get delayed, canceled, and neutered while niche or even bad features get implemented instead.
The compiler can trivially turn this into a jump, but the developer doesn't have enough context to construct any kind of loop:
function ap(f, v) { return f(v); }