I believe tail call optimization was removed from Node.js after v7 due to issues with debugging but please please please someone tell me I am wrong. Tell me TCO is still available in node...
i swear this is the best video to this that i could find, every other channel tries to explain this using fibonacci or something that is too complicated for my small brain to understand at 1 am.
@NWCalvank I tried your example on chrome's console. But the stack seems to be getting collected throughout unless poping begins. So how exactly is it benifitial?
Great explanation! The only thing that's kinda annoying is that the keyboard is very load when listening with headphone.. maybe place it more far away from the keyboard?
How does the compiler engine know that it doesn't need the result from before (in your tail call example)? It's still calling the same function name, so wouldn't this still affect the stack? Is the compiler smart enough to know that 'count' was all you really cared about? (and if that is the case, is that because 'count' was being returned instead of the result of the 'function' size being returned?
I'll attempt to explain in a way that I think answers the question. Let me know if it's not quite what you were asking... So, there are two things going on: Proper Tail Calls (PTC) and Tail Call Optimization (TCO). PTC is done by the developer. He/she implements PTC by placing the recursive call in the tail call position. When implemented properly, there is a new instance of the function that has all of the arguments that it needs in order to do its job. TCO is done by the JS engine. I can't speak to how this is implemented because it's not my area of expertise. But the idea is that the engine can recognize a PTC, initialize the function with its arguments, and then remove the previous instance of that function (because it is no longer needed). So, yes, the JS engine is 'smart enough' to recognize that the previous instance of the function is no longer needed. This is because there is no longer a reference to it. If we had something like: const sum = ([x, y, ...ys]) => ys.length === 0 ? x + y : sum([ x + y, ...ys ]) We know that: sum([45, 10]) // returns 55 It doesn't matter how we got to that final function call. The rest of the 'stack' is irrelevant. So, even if we went: sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]) to sum([3, 3, 4, 5, 6, 7, 8, 9, 10 ]) to sum([6, 4, 5, 6, 7, 8, 9, 10 ]) ... to sum([45, 10 ]) Each of those calls is independent. So, the engine can remove those old instances. Does that make sense?
I'm not aware of the support for TCO in Node, no. I typically only end up using recursion in very specific situations in JS, anyway. And, fortunately, I've known the data size or have been implementing something that doesn't have memory concerns anytime I have chosen recursion :)
as usual, awesome. I assume setting an implicit count variable is kind f useless since you won't do anything with it. It becomes usefull when passing explicitly a variable at function call
Implementing this with a count variable would mean initializing it at zero and then mutating it, which we want to avoid in functional programming. Does that make sense?
I believe tail call optimization was removed from Node.js after v7 due to issues with debugging but please please please someone tell me I am wrong. Tell me TCO is still available in node...
It looks like you're right! We lost one of my favourite features
@@NWCalvank Say it aint so! Looks like its trampolines from now on then.
i swear this is the best video to this that i could find, every other channel tries to explain this using fibonacci or something that is too complicated for my small brain to understand at 1 am.
Thank you this was great! It was concise and straightforward to understand.
Thanks for this video! Fantastic explanation.
@NWCalvank I tried your example on chrome's console. But the stack seems to be getting collected throughout unless poping begins. So how exactly is it benifitial?
I didn't know JS had destructuring! That is awesome. JS feels more and more like haskell!
Destructuring is my one true love
Great video dud!
Great explanation!
The only thing that's kinda annoying is that the keyboard is very load when listening with headphone.. maybe place it more far away from the keyboard?
Thanks for the feedback. I'll try to get a proper microphone/setup in the next couple weeks
thanks bro
So, this is not yet supported?
kangax.github.io/compat-table/es6/#test-proper_tail_calls_(tail_call_optimisation)
How does the compiler engine know that it doesn't need the result from before (in your tail call example)? It's still calling the same function name, so wouldn't this still affect the stack? Is the compiler smart enough to know that 'count' was all you really cared about? (and if that is the case, is that because 'count' was being returned instead of the result of the 'function' size being returned?
I'll attempt to explain in a way that I think answers the question. Let me know if it's not quite what you were asking...
So, there are two things going on: Proper Tail Calls (PTC) and Tail Call Optimization (TCO).
PTC is done by the developer. He/she implements PTC by placing the recursive call in the tail call position. When implemented properly, there is a new instance of the function that has all of the arguments that it needs in order to do its job.
TCO is done by the JS engine. I can't speak to how this is implemented because it's not my area of expertise. But the idea is that the engine can recognize a PTC, initialize the function with its arguments, and then remove the previous instance of that function (because it is no longer needed).
So, yes, the JS engine is 'smart enough' to recognize that the previous instance of the function is no longer needed. This is because there is no longer a reference to it.
If we had something like:
const sum = ([x, y, ...ys]) => ys.length === 0 ? x + y : sum([ x + y, ...ys ])
We know that:
sum([45, 10]) // returns 55
It doesn't matter how we got to that final function call. The rest of the 'stack' is irrelevant.
So, even if we went:
sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ])
to
sum([3, 3, 4, 5, 6, 7, 8, 9, 10 ])
to
sum([6, 4, 5, 6, 7, 8, 9, 10 ])
...
to
sum([45, 10 ])
Each of those calls is independent. So, the engine can remove those old instances. Does that make sense?
Do you know if this is implemented on node? I guess no, since node relies on V8
I'm not aware of the support for TCO in Node, no. I typically only end up using recursion in very specific situations in JS, anyway. And, fortunately, I've known the data size or have been implementing something that doesn't have memory concerns anytime I have chosen recursion :)
as usual, awesome. I assume setting an implicit count variable is kind f useless since you won't do anything with it. It becomes usefull when passing explicitly a variable at function call
Implementing this with a count variable would mean initializing it at zero and then mutating it, which we want to avoid in functional programming.
Does that make sense?
Good one.
Thanks :)