New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response to the proposal to add explicit tail call syntax to ECMAScript #535

Open
msaboff opened this Issue Apr 12, 2016 · 89 comments

Comments

Projects
None yet
@msaboff
Contributor

msaboff commented Apr 12, 2016

After some discussion with other JavaScriptCore team members, we at Apple cannot support the suggested change to make tail calls explicit via syntax due to the expected web incompatibilities those changes will create.

Given that tail calls are currently part of the ES6 and draft ES7 specification, a compliant implementation should implement tail calls as described in those specifications. Compliance with any proposed changes would not occur for almost two years since the earliest that any proposed tail call changes could be adopted would be for the ES2017 (ES8?) specification. In the mean time web pages and Javascript applications will be created that are susceptible to future breakage.

In addition to the current JavaScriptCore implementation, it is likely that other browser venders will implement Tail Calls compliant with the current standard. Let’s consider the changes to tail calls as suggested at the March 2016 TC-39 meeting and the impact it would have on Safari and any other compliant implementations that will be shipped this year. I’d like to cover what I understood was being presented at the March meeting, but I will also cover two other reasonable variants of that proposal and my assessment of their suitability.

  1. Tail calls based on tail position are optional. Tail calls based on opt-in syntax are required.
    There will be web pages and web applications developed starting this year that take advantage of tail calls as currently specified. Those web pages would become susceptible to breakage should we change the specification. Consider web pages that take advantage of tail calls as intended in the current specification. The Javascript written for such a web page assumes unlimited tail calls. Obviously, those pages won't work on an implementation that doesn’t support tail calls. If one browser decides to stop supporting implicit tail call behavior, they break that class of web pages. Therefore early adopters like us need to continue to support the currently specified behavior. The implication of this is that ES6 tail call behavior cannot be made optional without compatibility issues for Safari. Other early adopting browsers have the same issue.

    If another browser decided to not support implicit tail calls, but waits for the proposed change and only implements explicit tail calls, they introduce cross browser incompatibilities. Certainly such a browser is not compatible when running a web page that depends on implicit tail calls and likely never will be. In addition, there would be at least another class of incompatibilities. Consider a web page that inadvertently makes infinite recursive calls. For browsers that waited for explicit tail calls, that web page could throw an out of memory exception that might be silently caught, after which the web page proceeds as expected. For Safari and other browsers that support implicit tail calls, that web page is stuck in an infinite loop. The error is in the web page, but the handling of the error by each browsers is vastly different depending on their support of implicit tail calls. We have seen this type of issue in the past and reduced our stack size to maintain cross browser compatibility.

    Approval of this proposal also encourages browser vendors to wait to implement the current ES6 specified tail call behavior. This selective delay by some implementations diminishes the purpose of the ECMAScript standard and the features contained therein. Selective support by various implementations will cause developers to delay their adoption of the programming patterns tail calls was designed to address. Again this only impacts early adopting browsers like Safari.

    The main problem with this proposal is that it relaxes normative behavior and makes it optional, effectively eliminating that behavior from the standard. After we work through the early adopter problems described above, we’d introduce a new problem: Developers don’t know if they can use tail calls based on tail position or not, since implementations vary. Feature testing for the optional tail call behavior would be difficult and cumbersome, given the current specification. Optional behavior without a feature test has little place in the standard and cannot be relied upon by implementors and developers alike.

    Given these web compatibility issues and related developer concerns, we reject this type of proposal.

  2. Tail calls based on tail position are forbidden. Tail calls based on opt-in syntax are required.
    A proposal based on this option requires that early adopting implementations, like Safari, need to change and stop supporting implicit tail calls. Those changes break web pages designed for the current spec as described above. It not only breaks those web pages, it would require that they be rewritten. The web breakage and subsequent rework by web developers caused by this option is much worse than with the first option.

    There will also be web pages that accidentally took advantage of and benefited from implicit tail calls. With this proposal, those web pages could break due to running out of stack space. These breakages would be confusing at best to the web page implementers and likely damage the perceived quality of Safari.

    Due to the breakage this imposes on Safari and web pages developed to use implicit tail calls, we also reject this type of proposal.

  3. Tail calls based on tail position are required. New syntax for verifying tail position is required.
    This is the only proposal that wouldn’t cause breakage. This proposal would be to add syntax to signify a tail call is intended, but wouldn’t change the normative nature of tail calls as currently specified. If the call is not in tail position, a syntax error is issued. Implicit tail calls as currently defined would still be normative and must be implemented by conforming implementations. This change is backward compatible. Pages developed to take advantage of proper tail calls without the new syntax would continue to work. Javascript code developed with the new syntax get additional checking and the added benefit that tail calls appear different in the source code. The usefulness of this change is minimal though as it adds optional syntax with little corresponding semantic changes.

    We recommend against this proposal, but our objection is not as strong as our objections to (1) and (2), since this proposal would not harm web compatibility. Our main concern is that this proposal could add confusion with very little benefit.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 12, 2016

Member

Interop is about how actual implementations match and how well they run code that exists. As far as I am aware there is no actual interop concern with regard to tail calls as tail calls are not implemented interoperably in browsers and will not be for some time. It is possible (and has occurred before) that a change to a ratified specification results in more interoperability rather than less. See for example myriad changes to functions in sloppy mode or removal of Proxy's enumerate trap (something Edge had already shipped). Can you clarify what websites that exist today or in the near future would break as a result of adopting a proposal like (1)?

An implementation can do implicit tail calls without violating the spec, though I agree developers would not choose to rely on the implicit tail calls as there is no guarantee they will work. That's exactly the case they're in today and will be until they can support only browsers that support tail calls. A syntactic sigil would actually help developers feature detect an otherwise very difficult to test for feature.

Member

bterlson commented Apr 12, 2016

Interop is about how actual implementations match and how well they run code that exists. As far as I am aware there is no actual interop concern with regard to tail calls as tail calls are not implemented interoperably in browsers and will not be for some time. It is possible (and has occurred before) that a change to a ratified specification results in more interoperability rather than less. See for example myriad changes to functions in sloppy mode or removal of Proxy's enumerate trap (something Edge had already shipped). Can you clarify what websites that exist today or in the near future would break as a result of adopting a proposal like (1)?

An implementation can do implicit tail calls without violating the spec, though I agree developers would not choose to rely on the implicit tail calls as there is no guarantee they will work. That's exactly the case they're in today and will be until they can support only browsers that support tail calls. A syntactic sigil would actually help developers feature detect an otherwise very difficult to test for feature.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 12, 2016

Contributor

A syntactic sigil would actually help developers feature detect

How do you propose they do that? With try..catch and Function(..) or eval(..)? What would happen if a browser landed this syntax (to support annotations of developer intent) but refused to actually optimize some tail calls for any of various reasons? Developers still wouldn't be able to rely upon the optimization, even if the syntax test passed.

My point is merely that feature-testing is a weak argument for the syntax addition, when what's already at stake here is that a standard was developed, voted upon, and began to be implemented, and then browsers started backing off from their commitments to it. I don't see how adding syntax (that we can hackily "feature test" for, at best) is going to give us developers any more reliability on PTC than we have in ES2015, which is to say, not much.

Side Note: I proposed real feature tests for stuff like this, through an API, and it was largely shot down.

I also suggested a hackish pattern for meta-programming with PTC wherein you structure your recursive code to attempt PTC recursion, but if the env kills it because of no TCO, then you just detect and restart. I had hoped this was nothing more than an interim sort of hack until PTC was guaranteed, but it sure sounds from the tone of discussion as if it may never be.

Feature-testing with syntax (that can as easily be ignored as implicit PTC) is not any more compelling to me. It won't buy me anything I don't already get with ES2015 and -- if it's call-site based instead of function-signifier based -- will make more footguns for my recursive programming, in the cases where I forget to add it.

Contributor

getify commented Apr 12, 2016

A syntactic sigil would actually help developers feature detect

How do you propose they do that? With try..catch and Function(..) or eval(..)? What would happen if a browser landed this syntax (to support annotations of developer intent) but refused to actually optimize some tail calls for any of various reasons? Developers still wouldn't be able to rely upon the optimization, even if the syntax test passed.

My point is merely that feature-testing is a weak argument for the syntax addition, when what's already at stake here is that a standard was developed, voted upon, and began to be implemented, and then browsers started backing off from their commitments to it. I don't see how adding syntax (that we can hackily "feature test" for, at best) is going to give us developers any more reliability on PTC than we have in ES2015, which is to say, not much.

Side Note: I proposed real feature tests for stuff like this, through an API, and it was largely shot down.

I also suggested a hackish pattern for meta-programming with PTC wherein you structure your recursive code to attempt PTC recursion, but if the env kills it because of no TCO, then you just detect and restart. I had hoped this was nothing more than an interim sort of hack until PTC was guaranteed, but it sure sounds from the tone of discussion as if it may never be.

Feature-testing with syntax (that can as easily be ignored as implicit PTC) is not any more compelling to me. It won't buy me anything I don't already get with ES2015 and -- if it's call-site based instead of function-signifier based -- will make more footguns for my recursive programming, in the cases where I forget to add it.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 12, 2016

Member

@getify let's try to keep this thread focused on Apple's objections to hearing proposals that alleviate other implementers' concerns. I've set up a GitHub repo where we can discuss the myriad other questions/issues involved. Feel free to start a new OP (I will also be opening issues to discuss some of the questions we know we have).

Member

bterlson commented Apr 12, 2016

@getify let's try to keep this thread focused on Apple's objections to hearing proposals that alleviate other implementers' concerns. I've set up a GitHub repo where we can discuss the myriad other questions/issues involved. Feel free to start a new OP (I will also be opening issues to discuss some of the questions we know we have).

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Apr 12, 2016

Contributor

There's something I'm trying to understand about this conversation:

"Proper Tail Calls" is the feature that is included in the ES2015 spec. It specifies a list of productions and requires engines to implement those productions as tail calls.

"Tail Call Optimization" is an alternative that opportunistically implements certain productions as tail calls, but offers no guarantees about when it happens.

From the perspective of ES5, nothing is stopping an engine from implementing TCO today. The additional debuggability constraint makes implementations less willing to ship it, but that's not something the spec directly addresses.

Aside: The Ruby VM has support for TCO, but requires you to use the "VM" interface, supply an extra flag, and compile the code separately, because the Ruby core team has concerns about debuggability. Because they have implemented the feature, we know that their concern is not implementation difficulty, but rather the impact on backtraces (and that they aren't using that as a smokescreen to avoid doing work).

Here's what I'm trying to understand:

  1. Since nothing is stopping JSC from implementing TCO in the absence of a spec blessing, there is no reason for JSC to revert the work, even if we completely removed PTC from JavaScript.
  2. Since other browsers haven't yet implemented PTC, there is no way for a web developer to rely on the behavior when writing recursive programs.
  3. There is nothing stopping Safari from making additional guarantees about PTC, so that Safari can avoid breaking developers who have come to rely on this functionality.

In addition, if we define an explicit syntax for PTC, that means that we, TC39, commit to keeping PTC in our critical path, and should avoid us regressing on engines that want to make an additional promise of PTC in the absence of an explicit opt-in.

Contributor

wycats commented Apr 12, 2016

There's something I'm trying to understand about this conversation:

"Proper Tail Calls" is the feature that is included in the ES2015 spec. It specifies a list of productions and requires engines to implement those productions as tail calls.

"Tail Call Optimization" is an alternative that opportunistically implements certain productions as tail calls, but offers no guarantees about when it happens.

From the perspective of ES5, nothing is stopping an engine from implementing TCO today. The additional debuggability constraint makes implementations less willing to ship it, but that's not something the spec directly addresses.

Aside: The Ruby VM has support for TCO, but requires you to use the "VM" interface, supply an extra flag, and compile the code separately, because the Ruby core team has concerns about debuggability. Because they have implemented the feature, we know that their concern is not implementation difficulty, but rather the impact on backtraces (and that they aren't using that as a smokescreen to avoid doing work).

Here's what I'm trying to understand:

  1. Since nothing is stopping JSC from implementing TCO in the absence of a spec blessing, there is no reason for JSC to revert the work, even if we completely removed PTC from JavaScript.
  2. Since other browsers haven't yet implemented PTC, there is no way for a web developer to rely on the behavior when writing recursive programs.
  3. There is nothing stopping Safari from making additional guarantees about PTC, so that Safari can avoid breaking developers who have come to rely on this functionality.

In addition, if we define an explicit syntax for PTC, that means that we, TC39, commit to keeping PTC in our critical path, and should avoid us regressing on engines that want to make an additional promise of PTC in the absence of an explicit opt-in.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 12, 2016

Contributor

there is no way for a web developer to rely on the behavior when writing recursive programs.

One of my above points is that I don't believe this to necessarily be true, depending on what we may mean by "rely". If "rely" is a binary feature test, yes true. But if "rely" is "hope for" progressive enhancement optimization, not true.

In the latter sense, the snippet I linked to above suggests that (at least some) recursive code can be written to attempt PTC and assume/hope for TCO of it, but catch if the engine has to kill it for no TCO, and then restart and repeat the process. Code that falls into the non-TCO path will inevitably run slower/less efficiently, but still run. And developers can indeed rely on (hope for) -- because ES2015 promised it -- that "slower" code to get to the "faster" path eventually.

This is not just theory, I actually did exactly this awhile back. And it's my current strategy for bridging from non-TCO to TCO.

Contributor

getify commented Apr 12, 2016

there is no way for a web developer to rely on the behavior when writing recursive programs.

One of my above points is that I don't believe this to necessarily be true, depending on what we may mean by "rely". If "rely" is a binary feature test, yes true. But if "rely" is "hope for" progressive enhancement optimization, not true.

In the latter sense, the snippet I linked to above suggests that (at least some) recursive code can be written to attempt PTC and assume/hope for TCO of it, but catch if the engine has to kill it for no TCO, and then restart and repeat the process. Code that falls into the non-TCO path will inevitably run slower/less efficiently, but still run. And developers can indeed rely on (hope for) -- because ES2015 promised it -- that "slower" code to get to the "faster" path eventually.

This is not just theory, I actually did exactly this awhile back. And it's my current strategy for bridging from non-TCO to TCO.

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Apr 12, 2016

Contributor

This is not just theory, I actually did exactly this awhile back. And it's my current strategy for bridging from non-TCO to TCO.

If at least one engine promises PTC (as Safari is doing), that's still a reasonable strategy :)

And if a lot of people use it, that will put pressure on the other engines to make the same promises. In other words, don't try to accomplish by force what we can accomplish with less risk by persuasion.

Contributor

wycats commented Apr 12, 2016

This is not just theory, I actually did exactly this awhile back. And it's my current strategy for bridging from non-TCO to TCO.

If at least one engine promises PTC (as Safari is doing), that's still a reasonable strategy :)

And if a lot of people use it, that will put pressure on the other engines to make the same promises. In other words, don't try to accomplish by force what we can accomplish with less risk by persuasion.

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Apr 12, 2016

Contributor

And it's my current strategy for bridging from non-TCO to TCO

Just so I'm sure I'm understanding, you mean PTC ("guaranteed TCO") not "more TCO in general" right?

Contributor

wycats commented Apr 12, 2016

And it's my current strategy for bridging from non-TCO to TCO

Just so I'm sure I'm understanding, you mean PTC ("guaranteed TCO") not "more TCO in general" right?

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

Interop is about how actual implementations match and how well they run code that exists.

This is the crux of our argument.

As far as I am aware there is no actual interop concern with regard to tail calls as tail calls are not implemented interoperably in browsers and will not be for some time. It is possible (and has occurred before) that a change to a ratified specification results in more interoperability rather than less. See for example myriad changes to functions in sloppy mode or removal of Proxy's enumerate trap (something Edge had already shipped).

Our point is that the proposed change would decrease interoperability. Some implementations will do implicit PTC and eventually all will do Syntactic Tail Calls (STC). But as @getify points out, feature testing for either difficult and kludgy at best. Adding STC complicates matters as both PTC and STC would need to be tested.

Can you clarify what websites that exist today or in the near future would break as a result of adopting a proposal like (1)?

There are no known websites that would break with proposal (1), optional PTC + future STC. There are also no known current websites that will break with ES6 PTC alone. My point is that one can easily envision a website written to take advantage of PTC that would break without them. Remember that the PTC feature was added to enable a pattern that doesn't work today. Part of the objection to (1) is that future cross browser compatibility could force WebKit/JavaScriptCore to eliminate PTC and only support STC. In the process we break websites written assuming PTC.

An implementation can do implicit tail calls without violating the spec, though I agree developers would not choose to rely on the implicit tail calls as there is no guarantee they will work. That's exactly the case they're in today and will be until they can support only browsers that support tail calls.

A spec compliant implementation would need to support PTC. Without broad support across major browsers, we introduce confusion that @getify points out.

Contributor

msaboff commented Apr 12, 2016

Interop is about how actual implementations match and how well they run code that exists.

This is the crux of our argument.

As far as I am aware there is no actual interop concern with regard to tail calls as tail calls are not implemented interoperably in browsers and will not be for some time. It is possible (and has occurred before) that a change to a ratified specification results in more interoperability rather than less. See for example myriad changes to functions in sloppy mode or removal of Proxy's enumerate trap (something Edge had already shipped).

Our point is that the proposed change would decrease interoperability. Some implementations will do implicit PTC and eventually all will do Syntactic Tail Calls (STC). But as @getify points out, feature testing for either difficult and kludgy at best. Adding STC complicates matters as both PTC and STC would need to be tested.

Can you clarify what websites that exist today or in the near future would break as a result of adopting a proposal like (1)?

There are no known websites that would break with proposal (1), optional PTC + future STC. There are also no known current websites that will break with ES6 PTC alone. My point is that one can easily envision a website written to take advantage of PTC that would break without them. Remember that the PTC feature was added to enable a pattern that doesn't work today. Part of the objection to (1) is that future cross browser compatibility could force WebKit/JavaScriptCore to eliminate PTC and only support STC. In the process we break websites written assuming PTC.

An implementation can do implicit tail calls without violating the spec, though I agree developers would not choose to rely on the implicit tail calls as there is no guarantee they will work. That's exactly the case they're in today and will be until they can support only browsers that support tail calls.

A spec compliant implementation would need to support PTC. Without broad support across major browsers, we introduce confusion that @getify points out.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 12, 2016

Contributor

you mean PTC ("guaranteed TCO") not "more TCO in general" right?

Yes, sorry for the imprecise wording.

Contributor

getify commented Apr 12, 2016

you mean PTC ("guaranteed TCO") not "more TCO in general" right?

Yes, sorry for the imprecise wording.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

@getify let's try to keep this thread focused on Apple's objections to hearing proposals that alleviate other implementers' concerns.

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

Contributor

msaboff commented Apr 12, 2016

@getify let's try to keep this thread focused on Apple's objections to hearing proposals that alleviate other implementers' concerns.

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

There's something I'm trying to understand about this conversation:

"Proper Tail Calls" is the feature that is included in the ES2015 spec. It specifies a list of productions and requires engines to implement those productions as tail calls.

"Tail Call Optimization" is an alternative that opportunistically implements certain productions as tail calls, but offers no guarantees about when it happens.

What we are talking about here is "Proper Tail Calls" (PTC).

In addition, if we define an explicit syntax for PTC, that means that we, TC39, commit to keeping PTC in our critical path, and should avoid us regressing on engines that want to make an additional promise of PTC in the absence of an explicit opt-in.

At that March '16 meeting, TC39 agreed to support PTC. The problem is that the adoption of STC coupled with changing PTC from normative to optional will likely necessitate that Safari and other WebKit based implementations will need to change to follow what other implementations do. If the optional behavior is only implemented by Safari, it will likely be problematic to be different than other browsers. In the process we will likely break web pages and applications written between now and then.

Contributor

msaboff commented Apr 12, 2016

There's something I'm trying to understand about this conversation:

"Proper Tail Calls" is the feature that is included in the ES2015 spec. It specifies a list of productions and requires engines to implement those productions as tail calls.

"Tail Call Optimization" is an alternative that opportunistically implements certain productions as tail calls, but offers no guarantees about when it happens.

What we are talking about here is "Proper Tail Calls" (PTC).

In addition, if we define an explicit syntax for PTC, that means that we, TC39, commit to keeping PTC in our critical path, and should avoid us regressing on engines that want to make an additional promise of PTC in the absence of an explicit opt-in.

At that March '16 meeting, TC39 agreed to support PTC. The problem is that the adoption of STC coupled with changing PTC from normative to optional will likely necessitate that Safari and other WebKit based implementations will need to change to follow what other implementations do. If the optional behavior is only implemented by Safari, it will likely be problematic to be different than other browsers. In the process we will likely break web pages and applications written between now and then.

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Apr 12, 2016

Contributor

At that March '16 meeting, TC39 agreed to support PTC. The problem is that the adoption of STC coupled with changing PTC from normative to optional will likely necessitate that Safari and other WebKit based implementations will need to change to follow what other implementations do. If the optional behavior is only implemented by Safari, it will likely be problematic to be different than other browsers. In the process we will likely break web pages and applications written between now and then.

Can you explain why Safari will feel that it needs to remove an optimization (TCO) simply because it's optional, and why Safari would not be able to make a strong claim to developers that on Safari PTC is guaranteed?

Contributor

wycats commented Apr 12, 2016

At that March '16 meeting, TC39 agreed to support PTC. The problem is that the adoption of STC coupled with changing PTC from normative to optional will likely necessitate that Safari and other WebKit based implementations will need to change to follow what other implementations do. If the optional behavior is only implemented by Safari, it will likely be problematic to be different than other browsers. In the process we will likely break web pages and applications written between now and then.

Can you explain why Safari will feel that it needs to remove an optimization (TCO) simply because it's optional, and why Safari would not be able to make a strong claim to developers that on Safari PTC is guaranteed?

@allenwb

This comment has been minimized.

Show comment
Hide comment
@allenwb

allenwb Apr 12, 2016

Member

Before we pour too much energy into this we should remember that PTC is in the ECMAScript specification because there was consensus among all the TC39 members to included it. To remove it would require a similar consensus. Is there any chance of TC39 getting such a consensus in the short term? Based upon may recollection of the March meeting discussion and this (and related) threats we seem to be far from having a removal consensus or any other concrete proposal for changing PTC portions of the language specification.

Perhaps our energy would be better spent on helping concerned implementors understand how they can successfully (and economically) deal with the standard as it currently exists.

(and regarding optional TCO, PTC is in the spec. because we (the TC39 delegates) know that JS programmers could not interoperably depend upon optional TCO and that we could not depend upon all implementation to bother implementing such an optional feature. We know there would be implementation push back and that is why it was specified as PTC and not TCO. We should not fold on this point with the first push back. Rather we should let this play out in the market for as long as it takes to resolve itself.)

Member

allenwb commented Apr 12, 2016

Before we pour too much energy into this we should remember that PTC is in the ECMAScript specification because there was consensus among all the TC39 members to included it. To remove it would require a similar consensus. Is there any chance of TC39 getting such a consensus in the short term? Based upon may recollection of the March meeting discussion and this (and related) threats we seem to be far from having a removal consensus or any other concrete proposal for changing PTC portions of the language specification.

Perhaps our energy would be better spent on helping concerned implementors understand how they can successfully (and economically) deal with the standard as it currently exists.

(and regarding optional TCO, PTC is in the spec. because we (the TC39 delegates) know that JS programmers could not interoperably depend upon optional TCO and that we could not depend upon all implementation to bother implementing such an optional feature. We know there would be implementation push back and that is why it was specified as PTC and not TCO. We should not fold on this point with the first push back. Rather we should let this play out in the market for as long as it takes to resolve itself.)

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 12, 2016

Member

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

Sorry, I did not get that from your original post, and I was trying to keep the conversation focused. In that case, can you elaborate on how STC makes feature detection harder?

Member

bterlson commented Apr 12, 2016

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

Sorry, I did not get that from your original post, and I was trying to keep the conversation focused. In that case, can you elaborate on how STC makes feature detection harder?

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

Can you explain why Safari will feel that it needs to remove an optimization (TCO) simply because it's optional, and why Safari would not be able to make a strong claim to developers that on Safari PTC is guaranteed?

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC). What the JavaScriptCore team has implemented is ES6 compliant PTC. Whether or not we or any web developer considers it also an optimization is moot and immaterial for this discussion.

I think I outlined in the initial post why we might feel compelled to eliminate PTC at some point after STC are implemented.

Contributor

msaboff commented Apr 12, 2016

Can you explain why Safari will feel that it needs to remove an optimization (TCO) simply because it's optional, and why Safari would not be able to make a strong claim to developers that on Safari PTC is guaranteed?

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC). What the JavaScriptCore team has implemented is ES6 compliant PTC. Whether or not we or any web developer considers it also an optimization is moot and immaterial for this discussion.

I think I outlined in the initial post why we might feel compelled to eliminate PTC at some point after STC are implemented.

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Apr 12, 2016

Contributor

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We are not talking about disallowing PTC.

What the JavaScriptCore team has implemented is ES6 compliant PTC.

Yes. That is true.

Whether or not we or any web developer considers it also an optimization is moot and immaterial for this discussion.

Can you please explain why JSC would feel that they need to remove their PTC implementation if other engines did not implement PTC?

Concretely, what are the interop concerns?

Contributor

wycats commented Apr 12, 2016

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We are not talking about disallowing PTC.

What the JavaScriptCore team has implemented is ES6 compliant PTC.

Yes. That is true.

Whether or not we or any web developer considers it also an optimization is moot and immaterial for this discussion.

Can you please explain why JSC would feel that they need to remove their PTC implementation if other engines did not implement PTC?

Concretely, what are the interop concerns?

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

Sorry, I did not get that from your original post, and I was trying to keep the conversation focused. In that case, can you elaborate on how STC makes feature detection harder?

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior. In ES6 (and draft ES7) PTC are normative. If a future version of ES made currently normative PTC optional, then developers need a PTC feature test. That is what proposal (1) would do, add the need for a PTC feature test. About the best way to feature test for PTC is to overflow the stack and catch. Note that the kangax ES 6 compatibility webpage makes recursive calls 1 million levels deep to feature test for PTC a total of three times. The kangax method is too simplistic as a browser might increase their stack size for other reasons. Having written an out-of-stack corner case test, I can tell you it takes some time to execute and a straightforward implementation would block execution during detection. There would be a brief growth industry for developers to write the best PTC feature test. Some of these feature tests might trigger latent bugs in various browsers.

The STC proposal could be amended to include a feature test capability, but it is my sense that there wouldn't be TC-39 committee support for such an amendment. Certainly adding a PTC feature test to a future version of ES, when PTC were made optional, seems problematic and would require developer rework of ES6 compliant web applications.

As @getify points out above, having STC doesn't solve the feature test, as an implementation may implement the syntax without making a true tail call. Eval'ing some code to see if is throws a SyntaxError seems a little weird to check for the absence of a feature. Yet it may not be sufficient to indicate an implementation supports STC. To be complete one might need / want to test that both PTC and STC actually make a true tail call. All 4 combinations could exist in deployed browser implementations.

Contributor

msaboff commented Apr 12, 2016

I think these comments are focused on our objection. Developers do not have a way to feature test support for PTC. In my opinion, the addition of STC doesn't make things better, it makes them worse.

Sorry, I did not get that from your original post, and I was trying to keep the conversation focused. In that case, can you elaborate on how STC makes feature detection harder?

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior. In ES6 (and draft ES7) PTC are normative. If a future version of ES made currently normative PTC optional, then developers need a PTC feature test. That is what proposal (1) would do, add the need for a PTC feature test. About the best way to feature test for PTC is to overflow the stack and catch. Note that the kangax ES 6 compatibility webpage makes recursive calls 1 million levels deep to feature test for PTC a total of three times. The kangax method is too simplistic as a browser might increase their stack size for other reasons. Having written an out-of-stack corner case test, I can tell you it takes some time to execute and a straightforward implementation would block execution during detection. There would be a brief growth industry for developers to write the best PTC feature test. Some of these feature tests might trigger latent bugs in various browsers.

The STC proposal could be amended to include a feature test capability, but it is my sense that there wouldn't be TC-39 committee support for such an amendment. Certainly adding a PTC feature test to a future version of ES, when PTC were made optional, seems problematic and would require developer rework of ES6 compliant web applications.

As @getify points out above, having STC doesn't solve the feature test, as an implementation may implement the syntax without making a true tail call. Eval'ing some code to see if is throws a SyntaxError seems a little weird to check for the absence of a feature. Yet it may not be sufficient to indicate an implementation supports STC. To be complete one might need / want to test that both PTC and STC actually make a true tail call. All 4 combinations could exist in deployed browser implementations.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 12, 2016

Contributor

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We are not talking about disallowing PTC.

Let's be very clear what we are talking about here. PTC are required for ES6 compliance. Some implementations are not planning on implementing PTC. Instead they are proposing the addition of STC and make PTC optional.

Neither I nor do I think those proposing STC are talking about TCO. The ES6 spec only talks about reusing stack space.

Contributor

msaboff commented Apr 12, 2016

We are not talking about removing an optimization (TCO) we are talking about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We are not talking about disallowing PTC.

Let's be very clear what we are talking about here. PTC are required for ES6 compliance. Some implementations are not planning on implementing PTC. Instead they are proposing the addition of STC and make PTC optional.

Neither I nor do I think those proposing STC are talking about TCO. The ES6 spec only talks about reusing stack space.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 12, 2016

Contributor

Just a quick clarification question (especially since I'm already guilty in this thread of imprecise wording): PTC is an optimization, right, in the sense that it prevents growth of the stack as the calls pile up? I am guilty of not really understanding the extent that TCO is different from PTC. In other words, proper tail calls, from a grammatical standpoint, seem irrelevant/pointless if they aren't implying the constant-stack-size thing on such calls, and that is the optimization I have in mind when I say TCO. So what additional optimization am I missing that TCO implies that PTC does not?

Contributor

getify commented Apr 12, 2016

Just a quick clarification question (especially since I'm already guilty in this thread of imprecise wording): PTC is an optimization, right, in the sense that it prevents growth of the stack as the calls pile up? I am guilty of not really understanding the extent that TCO is different from PTC. In other words, proper tail calls, from a grammatical standpoint, seem irrelevant/pointless if they aren't implying the constant-stack-size thing on such calls, and that is the optimization I have in mind when I say TCO. So what additional optimization am I missing that TCO implies that PTC does not?

@allenwb

This comment has been minimized.

Show comment
Hide comment
@allenwb

allenwb Apr 12, 2016

Member

@getify no PTC is not an optimization. It is instead part of the required semantics of certain calls.

An "optimization" is generally something unobservable (ie, semantic preserving) that an implementation might (ie, optionally) do to to enhance performance or some other interesting metric. That difference between PTC and TCO is that PTC is required (and observable) semantics. TCO is just an optimization (assuming that you don't consider stack overflow on unbounded recursion part of the semantics of call)

Member

allenwb commented Apr 12, 2016

@getify no PTC is not an optimization. It is instead part of the required semantics of certain calls.

An "optimization" is generally something unobservable (ie, semantic preserving) that an implementation might (ie, optionally) do to to enhance performance or some other interesting metric. That difference between PTC and TCO is that PTC is required (and observable) semantics. TCO is just an optimization (assuming that you don't consider stack overflow on unbounded recursion part of the semantics of call)

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 13, 2016

Contributor

Just a quick clarification question .... So what additional optimization am I missing that TCO implies that PTC does not?

Proper Tail Calls as specified in ES6 only require reusing stack space. A Tail Call Optimization might also use different instructions to make and/or return from a call. It might have different prologue / epilogue code that would eliminate the saving and restoring of registers. Argument count and type checking code might be bypassed when tail calling to the same function. A good compiler could turn a tail call to self into a loop. As @allenwb says, these are unobservable performance enhancements beyond the observable stack space reuse.

Contributor

msaboff commented Apr 13, 2016

Just a quick clarification question .... So what additional optimization am I missing that TCO implies that PTC does not?

Proper Tail Calls as specified in ES6 only require reusing stack space. A Tail Call Optimization might also use different instructions to make and/or return from a call. It might have different prologue / epilogue code that would eliminate the saving and restoring of registers. Argument count and type checking code might be bypassed when tail calling to the same function. A good compiler could turn a tail call to self into a loop. As @allenwb says, these are unobservable performance enhancements beyond the observable stack space reuse.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 13, 2016

Contributor

@allenwb @msaboff thanks for the clarifications.

Contributor

getify commented Apr 13, 2016

@allenwb @msaboff thanks for the clarifications.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 13, 2016

Member

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior

I don't believe this is true - in fact, it seems like the opposite to me. Can you elaborate or link to notes?

I still am missing something critical here, though, so please forgive me. I don't understand how feature detection with PTC is easier than with STC. Scenario: I'm a dev who wants to use either my PTC/STC-dependent algorithm or a less efficient one (possibly transpiled). Basically only option with PTC is recurse a bunch of times and look for an error, unreliable as you say. If we have STC, the situation is at most just as bad, but can be made easier by taking advantage of the fact that no one will actually ship a browser with STC syntax but without STC semantics. Testing for syntax seems like a very easy litmus test that will be valuable in practice. Thoughts?

Member

bterlson commented Apr 13, 2016

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior

I don't believe this is true - in fact, it seems like the opposite to me. Can you elaborate or link to notes?

I still am missing something critical here, though, so please forgive me. I don't understand how feature detection with PTC is easier than with STC. Scenario: I'm a dev who wants to use either my PTC/STC-dependent algorithm or a less efficient one (possibly transpiled). Basically only option with PTC is recurse a bunch of times and look for an error, unreliable as you say. If we have STC, the situation is at most just as bad, but can be made easier by taking advantage of the fact that no one will actually ship a browser with STC syntax but without STC semantics. Testing for syntax seems like a very easy litmus test that will be valuable in practice. Thoughts?

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 13, 2016

Contributor

no one will actually ship a browser with STC syntax but without STC semantics

So you say, but I don't think there's anything that developers could actually rely on there. For example, the Mozilla folks might not want to honor a STC on a cross-realm call. AFAIK, the jury is still out on whether that case would cause an affirmative catchable error or just a warning. If it turns out to be a warning, for example, then a developer may not be able to rely on just a general feature test for STC as they'd need to check specific STC cases in tests.

Also, IIUC, a call-site may possibly not obviously look cross-realm but actually be cross-realm, so developers would have to be a lot more careful about the assumptions they make from FTs.

Bottom line, introducing STC alongside PTC would, in general, lead to the need to test both. I think that was @msaboff's point (at least I hope I got it right).

Contributor

getify commented Apr 13, 2016

no one will actually ship a browser with STC syntax but without STC semantics

So you say, but I don't think there's anything that developers could actually rely on there. For example, the Mozilla folks might not want to honor a STC on a cross-realm call. AFAIK, the jury is still out on whether that case would cause an affirmative catchable error or just a warning. If it turns out to be a warning, for example, then a developer may not be able to rely on just a general feature test for STC as they'd need to check specific STC cases in tests.

Also, IIUC, a call-site may possibly not obviously look cross-realm but actually be cross-realm, so developers would have to be a lot more careful about the assumptions they make from FTs.

Bottom line, introducing STC alongside PTC would, in general, lead to the need to test both. I think that was @msaboff's point (at least I hope I got it right).

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 13, 2016

Member

In a world where Mozilla ships with just a warning, a library author that wants to feature detect the presence of STC has two options: 1, simply test syntax and not explicitly support cross realm calls (very reasonable, cross realm calls are in practice very rare today, and not something developers typically code defensively against as there are other complexities involved), or 2) do exactly what you have to do today with PTC and actually set up a cross-realm call chain and see what happens. So unless I'm missing something (probably am), at worst STC seems as bad as PTC for feature detection, but at best allows a very simple feature detection method that will in practice work for most people.

Member

bterlson commented Apr 13, 2016

In a world where Mozilla ships with just a warning, a library author that wants to feature detect the presence of STC has two options: 1, simply test syntax and not explicitly support cross realm calls (very reasonable, cross realm calls are in practice very rare today, and not something developers typically code defensively against as there are other complexities involved), or 2) do exactly what you have to do today with PTC and actually set up a cross-realm call chain and see what happens. So unless I'm missing something (probably am), at worst STC seems as bad as PTC for feature detection, but at best allows a very simple feature detection method that will in practice work for most people.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 13, 2016

Contributor

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior

I don't believe this is true - in fact, it seems like the opposite to me. Can you elaborate or link to notes?

I don't know if it is in the notes, but I suggested at one point feature testing some other feature and the response was that the committee wasn't going to go back to that kind of world. Besides, normative behavior doesn't need a feature test.

I still am missing something critical here, though, so please forgive me. I don't understand how feature detection with PTC is easier than with STC. Scenario: I'm a dev who wants to use either my PTC/STC-dependent algorithm or a less efficient one (possibly transpiled). Basically only option with PTC is recurse a bunch of times and look for an error, unreliable as you say. If we have STC, the situation is at most just as bad, but can be made easier by taking advantage of the fact that no one will actually ship a browser with STC syntax but without STC semantics. Testing for syntax seems like a very easy litmus test that will be valuable in practice. Thoughts?

Feature testing for PTC or STC would be about the same if a developer wanted to make sure that each really made the tail calls they expected. Having to feature test for both and deciding what to do based on the combinations complicates things. Consider Safari version N supports PTC but not STC. Later, version N+1 supports both PTC and STC. It is likely that other browsers will support only STC. At some point, good web apps will need to check for PTC and STC, and select among three broad code paths. This seems unruly for developers. That's one way that STC makes tail call feature testing more complicated. Given this complexity, a developer decides to only checks STC syntax and drops their PTC check and corresponding path. The result is that we'll lose out for users with Safari N due to the complexity of checking and coding for both PTC and STC.

Contributor

msaboff commented Apr 13, 2016

During various TC-39 discussion, it has been made clear the there should never be the need for feature testing Spec'ed ES normative behavior

I don't believe this is true - in fact, it seems like the opposite to me. Can you elaborate or link to notes?

I don't know if it is in the notes, but I suggested at one point feature testing some other feature and the response was that the committee wasn't going to go back to that kind of world. Besides, normative behavior doesn't need a feature test.

I still am missing something critical here, though, so please forgive me. I don't understand how feature detection with PTC is easier than with STC. Scenario: I'm a dev who wants to use either my PTC/STC-dependent algorithm or a less efficient one (possibly transpiled). Basically only option with PTC is recurse a bunch of times and look for an error, unreliable as you say. If we have STC, the situation is at most just as bad, but can be made easier by taking advantage of the fact that no one will actually ship a browser with STC syntax but without STC semantics. Testing for syntax seems like a very easy litmus test that will be valuable in practice. Thoughts?

Feature testing for PTC or STC would be about the same if a developer wanted to make sure that each really made the tail calls they expected. Having to feature test for both and deciding what to do based on the combinations complicates things. Consider Safari version N supports PTC but not STC. Later, version N+1 supports both PTC and STC. It is likely that other browsers will support only STC. At some point, good web apps will need to check for PTC and STC, and select among three broad code paths. This seems unruly for developers. That's one way that STC makes tail call feature testing more complicated. Given this complexity, a developer decides to only checks STC syntax and drops their PTC check and corresponding path. The result is that we'll lose out for users with Safari N due to the complexity of checking and coding for both PTC and STC.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 13, 2016

Member

Besides, normative behavior doesn't need a feature test.

Maybe we're talking about different things. Feature detection is most frequently used to detect whether an implementation supports some normative behavior so that they can, for eg., use built-in WeakMap when available, otherwise a polyfill.

I see what you are saying now about the difficulty, though! I was comparing the cost of STC by itself rather than in addition to PTC.

Member

bterlson commented Apr 13, 2016

Besides, normative behavior doesn't need a feature test.

Maybe we're talking about different things. Feature detection is most frequently used to detect whether an implementation supports some normative behavior so that they can, for eg., use built-in WeakMap when available, otherwise a polyfill.

I see what you are saying now about the difficulty, though! I was comparing the cost of STC by itself rather than in addition to PTC.

@rossberg

This comment has been minimized.

Show comment
Hide comment
@rossberg

rossberg Apr 13, 2016

Member

On 13 April 2016 at 01:30, Michael Saboff notifications@github.com wrote:

We are not talking about removing an optimization (TCO) we are talking
about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We
are not talking about disallowing PTC.

Let's be very clear what we are talking about here. PTC are required for
ES6 compliance. Some implementations are not planning on implementing PTC.
Instead they are proposing the addition of STC and make PTC optional.

Note that TC39 agreed to adopt the "train model", or the "living spec".
That is, we continuously improve the spec, and only put stamps on it once a
year, mainly for bureaucratic reasons.

One side effect of this is that we do not do errata anymore. If we find
problems with a version of the spec, we just fix it in the next one. We
have done so before, see e.g. the changes around proxies or local functions.

In the old world, we might have put changes like the one under discussion
into the erratum category, but we got rid of that device, under the
assumption that everybody agreed to the above model.

I don't see the interop issue or any complication with feature testing if
we replace PTC with STC -- quite the opposite, in fact. The only way we
could practically get into a situation is if some browser shipped a
semantics before we have resolved this discussion. That's why Chrome has
pulled PTC from v51, although it was ready.

@allenwb, agreed with your description of the past, but as we all know, the
ES6 proposal process was utterly inadequate. By the current process,
several of the features in the current spec (and that includes tail calls)
would barely be at stage 3. So I think there is no shame in taking some
liberty to revisit some of the decisions where it is not too late.

Member

rossberg commented Apr 13, 2016

On 13 April 2016 at 01:30, Michael Saboff notifications@github.com wrote:

We are not talking about removing an optimization (TCO) we are talking
about removing Proper Tail Calls (PTC).

We are talking about making TCO optional without an explicit opt-in. We
are not talking about disallowing PTC.

Let's be very clear what we are talking about here. PTC are required for
ES6 compliance. Some implementations are not planning on implementing PTC.
Instead they are proposing the addition of STC and make PTC optional.

Note that TC39 agreed to adopt the "train model", or the "living spec".
That is, we continuously improve the spec, and only put stamps on it once a
year, mainly for bureaucratic reasons.

One side effect of this is that we do not do errata anymore. If we find
problems with a version of the spec, we just fix it in the next one. We
have done so before, see e.g. the changes around proxies or local functions.

In the old world, we might have put changes like the one under discussion
into the erratum category, but we got rid of that device, under the
assumption that everybody agreed to the above model.

I don't see the interop issue or any complication with feature testing if
we replace PTC with STC -- quite the opposite, in fact. The only way we
could practically get into a situation is if some browser shipped a
semantics before we have resolved this discussion. That's why Chrome has
pulled PTC from v51, although it was ready.

@allenwb, agreed with your description of the past, but as we all know, the
ES6 proposal process was utterly inadequate. By the current process,
several of the features in the current spec (and that includes tail calls)
would barely be at stage 3. So I think there is no shame in taking some
liberty to revisit some of the decisions where it is not too late.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 13, 2016

Contributor

@rossberg-chromium There is already production code (which I wrote) that is expecting eventually for PTC to "optimize" (aka improve the efficiency of) it. If I thought of that adaptive pattern (see above), there's a chance others have too, and I imagine it would be difficult to find in code searches. This is not a zero-cost change to revisit and do away with PTC in favor of STC more than a year after the spec was finalized.

A change from PTC to STC means that one cannot feasibly write adaptive recursive code the way I've suggested that merely progressively enhances once a browser lands the support. It means that the code in question absolutely has to be changed (and I'm not on that project anymore). Either that code path will have to be forked, with some sort of hard feature-test to select the STC or the non-recursive, or it has to be made entirely un-recursive until some magical future date when all supported browsers have STC.

That is a much less friendly path to migration to tail calls. If your usual "cost models" only involve looking at existing deployed code that will break, I would suggest you also have to consider the additional migration cost of syntax-annotated versus implied "optimization".

Contributor

getify commented Apr 13, 2016

@rossberg-chromium There is already production code (which I wrote) that is expecting eventually for PTC to "optimize" (aka improve the efficiency of) it. If I thought of that adaptive pattern (see above), there's a chance others have too, and I imagine it would be difficult to find in code searches. This is not a zero-cost change to revisit and do away with PTC in favor of STC more than a year after the spec was finalized.

A change from PTC to STC means that one cannot feasibly write adaptive recursive code the way I've suggested that merely progressively enhances once a browser lands the support. It means that the code in question absolutely has to be changed (and I'm not on that project anymore). Either that code path will have to be forked, with some sort of hard feature-test to select the STC or the non-recursive, or it has to be made entirely un-recursive until some magical future date when all supported browsers have STC.

That is a much less friendly path to migration to tail calls. If your usual "cost models" only involve looking at existing deployed code that will break, I would suggest you also have to consider the additional migration cost of syntax-annotated versus implied "optimization".

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 13, 2016

Member

I don't see the interop issue or any complication with feature testing if we replace PTC with STC -- quite the opposite, in fact. The only way we could practically get into a situation is if some browser shipped a semantics before we have resolved this discussion.

Yeah that's the part I was having trouble understanding as well. @msaboff is Safari shipping imminently with PTC enabled?

Member

bterlson commented Apr 13, 2016

I don't see the interop issue or any complication with feature testing if we replace PTC with STC -- quite the opposite, in fact. The only way we could practically get into a situation is if some browser shipped a semantics before we have resolved this discussion.

Yeah that's the part I was having trouble understanding as well. @msaboff is Safari shipping imminently with PTC enabled?

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson Apr 13, 2016

Member

There is already production code (which I wrote) that is expecting eventually for PTC to "optimize" (aka improve the efficiency of) it

Part of the motivation for me to re-examine this issue is the perception that PTC makes your code faster, the fact that much code exists that happens to include tail calls, and the fact that Chakra isn't sure yet how we can implement tail calls without regressing performance of function calls and effectively de-optimizing your program (which, presumably, doesn't care about the main benefit of PTC of avoiding stack growth since it runs fine without PTC).

Member

bterlson commented Apr 13, 2016

There is already production code (which I wrote) that is expecting eventually for PTC to "optimize" (aka improve the efficiency of) it

Part of the motivation for me to re-examine this issue is the perception that PTC makes your code faster, the fact that much code exists that happens to include tail calls, and the fact that Chakra isn't sure yet how we can implement tail calls without regressing performance of function calls and effectively de-optimizing your program (which, presumably, doesn't care about the main benefit of PTC of avoiding stack growth since it runs fine without PTC).

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify Apr 13, 2016

Contributor

Part of the motivation for me to re-examine this issue is the perception that PTC makes your code faster,

Make sure that you are doing an apples-to-apples comparison in that analysis. The comparison should include whether your implemented PTC would be slower, equal to, or faster (my strong intuition) than the try..catch based adaptive version I've suggested. It's not just whether a normal simple recursive program gets faster if PTC is in place, but whether code that runs fully and correctly, even to millions of call levels, in a non-PTC'd way, gets any faster if PTC is in place.

Also, "faster" is not the only concern. Memory efficiency/churn is also a strong motivating factor.

Contributor

getify commented Apr 13, 2016

Part of the motivation for me to re-examine this issue is the perception that PTC makes your code faster,

Make sure that you are doing an apples-to-apples comparison in that analysis. The comparison should include whether your implemented PTC would be slower, equal to, or faster (my strong intuition) than the try..catch based adaptive version I've suggested. It's not just whether a normal simple recursive program gets faster if PTC is in place, but whether code that runs fully and correctly, even to millions of call levels, in a non-PTC'd way, gets any faster if PTC is in place.

Also, "faster" is not the only concern. Memory efficiency/churn is also a strong motivating factor.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 13, 2016

Contributor

@msaboff is Safari shipping imminently with PTC enabled?

Safari will ship PTC as part of the next release. I cannot comment on the schedule of that release.

Contributor

msaboff commented Apr 13, 2016

@msaboff is Safari shipping imminently with PTC enabled?

Safari will ship PTC as part of the next release. I cannot comment on the schedule of that release.

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan Apr 13, 2016

Member

I'm not sure which browsers the OP is concerned about compatibility with. The only browsers which seemed to ship TCO turned on are Safari Tech Preview 1, and some previous Chrome Canary versions, though not the current one. It would be surprising if someone published a website which worked only on those, and not in any browser in a stable release version. We're just talking about compatibility with future Safari releases, and code which expected ES2015 to be implemented unchanged (which will not happen)?

@msaboff, we have co-championed a proposal to observably change the ES2015 RegExp semantics in a couple ways. In theory, someone could have created a website which depends on the exact ES2015 semantics. However, web compatibility has to be evaluated pragmatically--in this case, it was the ES2015 semantics which were web-incompatible, even though the spec had been ratified.

Similarly, it seems that proper tail calls cannot be implemented across browsers in a completely correct way, or meeting user performance and debugging needs, so I'd say it belongs in the same bucket of the small set of things that we need to revisit from ES2015. This is not an unboundedly large set, as Chrome, for one, ships all other major ES2015 features in the current Canary.

Member

littledan commented Apr 13, 2016

I'm not sure which browsers the OP is concerned about compatibility with. The only browsers which seemed to ship TCO turned on are Safari Tech Preview 1, and some previous Chrome Canary versions, though not the current one. It would be surprising if someone published a website which worked only on those, and not in any browser in a stable release version. We're just talking about compatibility with future Safari releases, and code which expected ES2015 to be implemented unchanged (which will not happen)?

@msaboff, we have co-championed a proposal to observably change the ES2015 RegExp semantics in a couple ways. In theory, someone could have created a website which depends on the exact ES2015 semantics. However, web compatibility has to be evaluated pragmatically--in this case, it was the ES2015 semantics which were web-incompatible, even though the spec had been ratified.

Similarly, it seems that proper tail calls cannot be implemented across browsers in a completely correct way, or meeting user performance and debugging needs, so I'd say it belongs in the same bucket of the small set of things that we need to revisit from ES2015. This is not an unboundedly large set, as Chrome, for one, ships all other major ES2015 features in the current Canary.

@concavelenz

This comment has been minimized.

Show comment
Hide comment
@concavelenz

concavelenz Apr 13, 2016

Here are my thoughts:

  • PTC are contentious (I'm curious how consensus was originally reached
    without an implementation proof)
  • the committee should consider declaring a misstep and moving PTC back to
    a stage three proposal (and encouraging vendors not to implement it the ES6
    semantics)
  • Explicit syntax doesn't help with the problems that arise with using PTC,
    it just postponed and slows down adoption so we don't notice it.
  • Explicit syntax does help folk that want to prevent the information loss
    associated with PTC and resulting debugging/error reporting issues as the
    explicit syntax makes it possible to ban.

If I'm understanding is correct and the main contention is postmortem
debugging (node core dumps, stack trace reports from the field), then:

  • If there is a solution for postmortem debugging and error reporting
    (which is critical for certain node.js and wide reaching web applications),
    then PTC can move forward as spec'd
  • If there is not a solution for postmortem debugging, then even explicit
    syntax need to be carefully considered, but it may be reasonable for move
    forward with it.

On Wed, Apr 13, 2016 at 9:21 AM, littledan notifications@github.com wrote:

I'm not sure which browsers the OP is concerned about compatibility with.
The only browsers which seemed to ship TCO turned on are Safari Tech
Preview 1, and some previous Chrome Canary versions, though not the current
one. It would be surprising if someone published a website which worked
only on those, and not in any browser in a stable release version. We're
just talking about compatibility with future Safari releases, and code
which expected ES2015 to be implemented unchanged (which will not happen)?

@msaboff https://github.com/msaboff, we have co-championed a proposal
to observably change the ES2015 RegExp semantics in a couple ways. In
theory, someone could have created a website which depends on the exact
ES2015 semantics. However, web compatibility has to be evaluated
pragmatically--in this case, it was the ES2015 semantics which were
web-incompatible, even though the spec had been ratified.

Similarly, it seems that proper tail calls cannot be implemented across
browsers in a completely correct way, or meeting user performance and
debugging needs, so I'd say it belongs in the same bucket of the small set
of things that we need to revisit from ES2015. This is not an unboundedly
large set, as Chrome, for one, ships all other major ES2015 features in the
current Canary.


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#535 (comment)

Here are my thoughts:

  • PTC are contentious (I'm curious how consensus was originally reached
    without an implementation proof)
  • the committee should consider declaring a misstep and moving PTC back to
    a stage three proposal (and encouraging vendors not to implement it the ES6
    semantics)
  • Explicit syntax doesn't help with the problems that arise with using PTC,
    it just postponed and slows down adoption so we don't notice it.
  • Explicit syntax does help folk that want to prevent the information loss
    associated with PTC and resulting debugging/error reporting issues as the
    explicit syntax makes it possible to ban.

If I'm understanding is correct and the main contention is postmortem
debugging (node core dumps, stack trace reports from the field), then:

  • If there is a solution for postmortem debugging and error reporting
    (which is critical for certain node.js and wide reaching web applications),
    then PTC can move forward as spec'd
  • If there is not a solution for postmortem debugging, then even explicit
    syntax need to be carefully considered, but it may be reasonable for move
    forward with it.

On Wed, Apr 13, 2016 at 9:21 AM, littledan notifications@github.com wrote:

I'm not sure which browsers the OP is concerned about compatibility with.
The only browsers which seemed to ship TCO turned on are Safari Tech
Preview 1, and some previous Chrome Canary versions, though not the current
one. It would be surprising if someone published a website which worked
only on those, and not in any browser in a stable release version. We're
just talking about compatibility with future Safari releases, and code
which expected ES2015 to be implemented unchanged (which will not happen)?

@msaboff https://github.com/msaboff, we have co-championed a proposal
to observably change the ES2015 RegExp semantics in a couple ways. In
theory, someone could have created a website which depends on the exact
ES2015 semantics. However, web compatibility has to be evaluated
pragmatically--in this case, it was the ES2015 semantics which were
web-incompatible, even though the spec had been ratified.

Similarly, it seems that proper tail calls cannot be implemented across
browsers in a completely correct way, or meeting user performance and
debugging needs, so I'd say it belongs in the same bucket of the small set
of things that we need to revisit from ES2015. This is not an unboundedly
large set, as Chrome, for one, ships all other major ES2015 features in the
current Canary.


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#535 (comment)

@geoffreygaren

This comment has been minimized.

Show comment
Hide comment
@geoffreygaren

geoffreygaren Apr 13, 2016

Since other browsers haven't yet implemented PTC, there is no way for a web developer to rely on the behavior when writing recursive programs.

An important point of clarification here: Though some developers deploy to the web and test their code across all major web browsers, not all do. Developers who write WebKit-specific code -- for app-embedded content or for purpose-specific websites -- will adopt PTC, intentionally or accidentally, even if PTC code wouldn't work in some major web browsers. A change away form PTC will break that code.

We think it should be a goal of the standard's evolution to avoid knowingly breaking existing standards-based code.

There is nothing stopping Safari from making additional guarantees about PTC, so that Safari can avoid breaking developers who have come to rely on this functionality.

Michael already described a few ways in which PTC support can break a website that was tested against a browser that didn't have PTC support. So, it is only safe to support PTC if the standard encourages consistent PTC support across implementations.

Since other browsers haven't yet implemented PTC, there is no way for a web developer to rely on the behavior when writing recursive programs.

An important point of clarification here: Though some developers deploy to the web and test their code across all major web browsers, not all do. Developers who write WebKit-specific code -- for app-embedded content or for purpose-specific websites -- will adopt PTC, intentionally or accidentally, even if PTC code wouldn't work in some major web browsers. A change away form PTC will break that code.

We think it should be a goal of the standard's evolution to avoid knowingly breaking existing standards-based code.

There is nothing stopping Safari from making additional guarantees about PTC, so that Safari can avoid breaking developers who have come to rely on this functionality.

Michael already described a few ways in which PTC support can break a website that was tested against a browser that didn't have PTC support. So, it is only safe to support PTC if the standard encourages consistent PTC support across implementations.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff Apr 13, 2016

Contributor

@littledan we are talking about web breakage between when Safari is released with PTC and some future point when STC are added and PTC become optional.

I'd like to bring this conversation back on topic. The verbal proposal made at the March TC-39 meeting was to add STC and make PTC optional. Recent posts on this thread are now talking about replacing PTC with STC. When I asked at the March meeting the PTC will always be allowed, I was assured that would be the case. Therefore the incompatibilities I present above are valid.

Contributor

msaboff commented Apr 13, 2016

@littledan we are talking about web breakage between when Safari is released with PTC and some future point when STC are added and PTC become optional.

I'd like to bring this conversation back on topic. The verbal proposal made at the March TC-39 meeting was to add STC and make PTC optional. Recent posts on this thread are now talking about replacing PTC with STC. When I asked at the March meeting the PTC will always be allowed, I was assured that would be the case. Therefore the incompatibilities I present above are valid.

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan Apr 13, 2016

Member

@geoffreygaren Although this is true in theory, I think we need to do this compatibility assessment pragmatically. Today, a developer would have to have to develop and test their website only in Safari Technology Preview 1 to encounter this issue, and their page would be broken in all major browser versions.

There's a lot of different threads of discussion here. What would you all think about splitting it up per topic? I opened up a bug in the tc39/proposal-ptc-syntax repository to discuss web compatibility concerns: tc39/proposal-ptc-syntax#3 . For the appropriateness of revisiting proper tail calls for the cross-realm case, could we discuss it at #508 , which is where the proposal lives?

Member

littledan commented Apr 13, 2016

@geoffreygaren Although this is true in theory, I think we need to do this compatibility assessment pragmatically. Today, a developer would have to have to develop and test their website only in Safari Technology Preview 1 to encounter this issue, and their page would be broken in all major browser versions.

There's a lot of different threads of discussion here. What would you all think about splitting it up per topic? I opened up a bug in the tc39/proposal-ptc-syntax repository to discuss web compatibility concerns: tc39/proposal-ptc-syntax#3 . For the appropriateness of revisiting proper tail calls for the cross-realm case, could we discuss it at #508 , which is where the proposal lives?

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan May 5, 2016

Member

Performance concerns of PTC

I believe it would be reasonable for TC39 to consider implementation constraints. PTC was specified before the current staging process took effect, so we didn’t get the two-implementation feedback that we would’ve gotten in the current process.

Now that we have this feedback from Microsoft, it might be reasonable for the committee to consider the diversity of reasonable implementation choices. Chakra chooses to use the Windows ABI, which comes with debugging integration with the rest of the platform. Something that’s implementable in one engine might not be practical in another. That’s part of the wisdom of the current requirement of two implementations for a new proposal to get to Stage 4.

STC would solve a performance problem by making tail calls pay-as-you-go, rather than a big all-in-one regression. Developers would likely only use STC where it provided the most value--in tail-call driven loops--rather than all over the place, as PTC is. If an engine does have nontrivial overhead for tail calls, then STC would make a regression on existing code, and PTC would not.

I believe at this point all browsers implementing ES2015 have put in a significant amount of work doing optimizations to make up for the performance challenges of the new language standard. But there are more concerns with this than just performance.

Because PTC elide stack frames, debugging would be more difficult.

You mentioned two approaches here, keeping a side stack when debugging, and turning off PTC when developer tools are open. Both have significant disadvantages.

Side stack: With the ShadowChicken approach, the stack trace may change based on details of garbage collection. When the garbage collector runs, it can remove frames which end in a tail call. These then won’t show up on a stack trace. This will remove valuable debugging information in some cases, when many JS engines work hard to maintain correct information.

Turning off PTC: Globally turning off PTC is a pretty heavy switch. It is a cross-cutting decision that will affect any nested library that the developer may not be aware of. If turning off PTC is a widely used feature of development tools, it reduces the value of the PTC feature itself, as libraries, application frameworks and users would avoid depending on the feature in order to continue functioning in this mode.

PTC will eliminate stack frame from telemetry data.

Many users have spoken up about how this telemetry data is important to them, including @davepacheco of Joyent, @jeffmo of Facebook, and various groups within Google (bug thread).

You cite the fact that Safari has shipped tech previous with PTC and not received bug reports about the missing stack trace. However, this issue wouldn’t result in a website simply doesn’t load. Instead, it will be that website authors will have more trouble debugging issues that come up on browsers that ship PTC. This means that users of browsers with PTC could suffer from worse user experience due to issues not being properly diagnosed and resolved, compared to users of browser which don’t have PTC.

However, currently, with a rather small population, major website owners are probably simply not seeing many of these shortened stack traces yet. They are likely able to do effective debugging for most of their current population, and might not even see any frequent enough reports from the small PTC population to draw concern.

Member

littledan commented May 5, 2016

Performance concerns of PTC

I believe it would be reasonable for TC39 to consider implementation constraints. PTC was specified before the current staging process took effect, so we didn’t get the two-implementation feedback that we would’ve gotten in the current process.

Now that we have this feedback from Microsoft, it might be reasonable for the committee to consider the diversity of reasonable implementation choices. Chakra chooses to use the Windows ABI, which comes with debugging integration with the rest of the platform. Something that’s implementable in one engine might not be practical in another. That’s part of the wisdom of the current requirement of two implementations for a new proposal to get to Stage 4.

STC would solve a performance problem by making tail calls pay-as-you-go, rather than a big all-in-one regression. Developers would likely only use STC where it provided the most value--in tail-call driven loops--rather than all over the place, as PTC is. If an engine does have nontrivial overhead for tail calls, then STC would make a regression on existing code, and PTC would not.

I believe at this point all browsers implementing ES2015 have put in a significant amount of work doing optimizations to make up for the performance challenges of the new language standard. But there are more concerns with this than just performance.

Because PTC elide stack frames, debugging would be more difficult.

You mentioned two approaches here, keeping a side stack when debugging, and turning off PTC when developer tools are open. Both have significant disadvantages.

Side stack: With the ShadowChicken approach, the stack trace may change based on details of garbage collection. When the garbage collector runs, it can remove frames which end in a tail call. These then won’t show up on a stack trace. This will remove valuable debugging information in some cases, when many JS engines work hard to maintain correct information.

Turning off PTC: Globally turning off PTC is a pretty heavy switch. It is a cross-cutting decision that will affect any nested library that the developer may not be aware of. If turning off PTC is a widely used feature of development tools, it reduces the value of the PTC feature itself, as libraries, application frameworks and users would avoid depending on the feature in order to continue functioning in this mode.

PTC will eliminate stack frame from telemetry data.

Many users have spoken up about how this telemetry data is important to them, including @davepacheco of Joyent, @jeffmo of Facebook, and various groups within Google (bug thread).

You cite the fact that Safari has shipped tech previous with PTC and not received bug reports about the missing stack trace. However, this issue wouldn’t result in a website simply doesn’t load. Instead, it will be that website authors will have more trouble debugging issues that come up on browsers that ship PTC. This means that users of browsers with PTC could suffer from worse user experience due to issues not being properly diagnosed and resolved, compared to users of browser which don’t have PTC.

However, currently, with a rather small population, major website owners are probably simply not seeing many of these shortened stack traces yet. They are likely able to do effective debugging for most of their current population, and might not even see any frequent enough reports from the small PTC population to draw concern.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

Developers would likely only use STC where it provided the most value--in tail-call driven loops--rather than all over the place, as PTC is.

I'm not sure this fits with how other evolutions of the language and "best practice" have played out. "Most" developers don't understand nuance/context in "best practice". "Most" developers actually prefer for "x is the new y" type best practices. For example, see "let is the new var", "arrow is the new function", etc.

Even if "let" or "arrow" was shown to create some performance problems in some engine, the overwhelming majority of developers would be using them across the board. Even for those of us who make our living in teaching JS to developers, I can't imagine there being widespread effective education around the nuances of when you'll want to use tail calls for memory and when you'll want to avoid tail calls for performance. I have intuitions about that stuff, but the majority of the JS population won't, and won't care. They'll follow whatever conventions are common for their framework of choice.

I can imagine certain language patterns (especially those which come from other languages transpiling to JS) taking a strong hold in this future "JS has tail calls" world, whenever it arrives, like FP, obviously. As that happens, we'll see a high percentage, even a majority, of calls being tail calls. It's entirely plausible we'll see "tail call is the new end-of-path function call" for that section of the JS ecosystem.

There's already several things that "FP in JS" devs do which are not strictly "fastest" or "most memory efficient", like for example filter(), map() and reduce() returning new arrays each time, or how bind() (for currying, not this) has been historically quite slow, though it's recently finally been improved. Those performance problems haven't stopped those techniques from being used. Tail calls being "slower" in an engine, in exchange for constant stack, isn't going to deter its usage either.

There's a likely future with a pretty heavy amount of tail calls happening in JS programs, and engines are going to have to do whatever they can in that future to try to optimize. I think it's a mistake to analyze now, in a world where no one can do tail calls in JS, that there's relatively few tail calls, and project that this will continue to be the case. It probably will change.

Contributor

getify commented May 5, 2016

Developers would likely only use STC where it provided the most value--in tail-call driven loops--rather than all over the place, as PTC is.

I'm not sure this fits with how other evolutions of the language and "best practice" have played out. "Most" developers don't understand nuance/context in "best practice". "Most" developers actually prefer for "x is the new y" type best practices. For example, see "let is the new var", "arrow is the new function", etc.

Even if "let" or "arrow" was shown to create some performance problems in some engine, the overwhelming majority of developers would be using them across the board. Even for those of us who make our living in teaching JS to developers, I can't imagine there being widespread effective education around the nuances of when you'll want to use tail calls for memory and when you'll want to avoid tail calls for performance. I have intuitions about that stuff, but the majority of the JS population won't, and won't care. They'll follow whatever conventions are common for their framework of choice.

I can imagine certain language patterns (especially those which come from other languages transpiling to JS) taking a strong hold in this future "JS has tail calls" world, whenever it arrives, like FP, obviously. As that happens, we'll see a high percentage, even a majority, of calls being tail calls. It's entirely plausible we'll see "tail call is the new end-of-path function call" for that section of the JS ecosystem.

There's already several things that "FP in JS" devs do which are not strictly "fastest" or "most memory efficient", like for example filter(), map() and reduce() returning new arrays each time, or how bind() (for currying, not this) has been historically quite slow, though it's recently finally been improved. Those performance problems haven't stopped those techniques from being used. Tail calls being "slower" in an engine, in exchange for constant stack, isn't going to deter its usage either.

There's a likely future with a pretty heavy amount of tail calls happening in JS programs, and engines are going to have to do whatever they can in that future to try to optimize. I think it's a mistake to analyze now, in a world where no one can do tail calls in JS, that there's relatively few tail calls, and project that this will continue to be the case. It probably will change.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

As a side note, this likely future where tail calls are used heavily and not just as some niche technique, is part of my objection to the call-site syntax approach (as opposed to the function level). The syn_tax_ literally becomes a tax on this coding pattern, one that's paid more heavily the more you want to take advantage of the pattern.

I can already see the future medium blog posts that criticize JS for adding syntactic cruft to otherwise "elegant tail call coding/recursion patterns". Someone will dig up this GH repo history and mumble something in the comments about it being because of old archaic engine limitations, and everyone will roll their eyes and mutter under the breath, "silly ol' ugly JS again".

Contributor

getify commented May 5, 2016

As a side note, this likely future where tail calls are used heavily and not just as some niche technique, is part of my objection to the call-site syntax approach (as opposed to the function level). The syn_tax_ literally becomes a tax on this coding pattern, one that's paid more heavily the more you want to take advantage of the pattern.

I can already see the future medium blog posts that criticize JS for adding syntactic cruft to otherwise "elegant tail call coding/recursion patterns". Someone will dig up this GH repo history and mumble something in the comments about it being because of old archaic engine limitations, and everyone will roll their eyes and mutter under the breath, "silly ol' ugly JS again".

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

If turning off PTC is a widely used feature of development tools

I've been assuming that the devtools story around tail call debugging would end up looking similar to how chrome devtools has the "script blackboxing" that makes a script opaque from the debugging perspective. I don't understand/believe the assertions that tail calls can't be made to work sensibly (even configurable) in devtools mode.

Contributor

getify commented May 5, 2016

If turning off PTC is a widely used feature of development tools

I've been assuming that the devtools story around tail call debugging would end up looking similar to how chrome devtools has the "script blackboxing" that makes a script opaque from the debugging perspective. I don't understand/believe the assertions that tail calls can't be made to work sensibly (even configurable) in devtools mode.

@saambarati

This comment has been minimized.

Show comment
Hide comment
@saambarati

saambarati May 5, 2016

@littledan said:

Side stack: With the ShadowChicken approach, the stack trace may change based on details of garbage collection. When the garbage collector runs, it can remove frames which end in a tail call. These then won’t show up on a stack trace. This will remove valuable debugging information in some cases, when many JS engines work hard to maintain correct information.

I don't think this is a concern for real debugging experiences. It's sufficiently rare to have an interactive debugging experience/session where you care about more than the top 5 frames. I know when I'm using a debugger, 99% of the time all I care about is the top most frame.

@littledan said:

Side stack: With the ShadowChicken approach, the stack trace may change based on details of garbage collection. When the garbage collector runs, it can remove frames which end in a tail call. These then won’t show up on a stack trace. This will remove valuable debugging information in some cases, when many JS engines work hard to maintain correct information.

I don't think this is a concern for real debugging experiences. It's sufficiently rare to have an interactive debugging experience/session where you care about more than the top 5 frames. I know when I'm using a debugger, 99% of the time all I care about is the top most frame.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

It's sufficiently rare to have an interactive debugging experience/session where you care about more than the top 5 frames.

Just articulated a compromise to many of the concerns here versus the motivations behind STC: "adaptive" tail-calling; that tail-calls only beyond a certain fixed limit: tc39/proposal-ptc-syntax#16

Contributor

getify commented May 5, 2016

It's sufficiently rare to have an interactive debugging experience/session where you care about more than the top 5 frames.

Just articulated a compromise to many of the concerns here versus the motivations behind STC: "adaptive" tail-calling; that tail-calls only beyond a certain fixed limit: tc39/proposal-ptc-syntax#16

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan May 5, 2016

Member

@getify Could you tell me more about how you'd solve the devtools/error.stack issues?

Member

littledan commented May 5, 2016

@getify Could you tell me more about how you'd solve the devtools/error.stack issues?

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

@littledan

the concern about turning off PTC while devtools/debugging and having that negatively impact (break) other libraries/frameworks that expect it to be in force, could be mitigated in the same way we deal with not wanting the noise of step-debugging in blackboxed scripts... meaning that PTC would continue to happen inside of any blackboxed scripts, even if devtools was open.

for the error.stack thing, the link I just posted is one potential compromise idea.

Contributor

getify commented May 5, 2016

@littledan

the concern about turning off PTC while devtools/debugging and having that negatively impact (break) other libraries/frameworks that expect it to be in force, could be mitigated in the same way we deal with not wanting the noise of step-debugging in blackboxed scripts... meaning that PTC would continue to happen inside of any blackboxed scripts, even if devtools was open.

for the error.stack thing, the link I just posted is one potential compromise idea.

@getify

This comment has been minimized.

Show comment
Hide comment
@getify

getify May 5, 2016

Contributor

I think it's also important to note that given there's no current JS support for these unlimited length call stacks, none of the error.stack telemetry stuff is handling any of that currently, so we wouldn't necessarily be taking that away in a breaking way. It's possible their infrastructure couldn't even handle if they all of a sudden received a stack that was hundreds of thousands of frames long.

One could imagine in the future the desire to have, for error.stack/telemetry purposes, a stack that was, for example, only the first 20 frames, the last 20 frames, and everything in between thrown away.

Contributor

getify commented May 5, 2016

I think it's also important to note that given there's no current JS support for these unlimited length call stacks, none of the error.stack telemetry stuff is handling any of that currently, so we wouldn't necessarily be taking that away in a breaking way. It's possible their infrastructure couldn't even handle if they all of a sudden received a stack that was hundreds of thousands of frames long.

One could imagine in the future the desire to have, for error.stack/telemetry purposes, a stack that was, for example, only the first 20 frames, the last 20 frames, and everything in between thrown away.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 5, 2016

Contributor

Since much of this discussion is based on assumptions with very little data, I decided to instrument JSC and see what happens on real webpages. I added compile time and runtime counters, basically to determine what percent of calls end up as PTC at compile time and then determine what percent of actual calls are PTC versus normal calls. The runtime result fit my gut instinct at ~5%. The percent of calls that get compiled to PTC surprised me on the low side, typically much less than 1%. I did not include true constructor calls in the data.

I performed 2 broad tests, first loading the top ~1000 Alexa sites, and then navigating specific sites that are high on the Alexa list that I could access without an account or with my own account. First the Alexa data, with raw numbers:

At compile time there were 6,683,375 calls of which 24,393 where PTCs (0.36%). While executing, 179,610,729 calls were made of which 8,396,396 where PTCs (4.67%).

Here is summary data for the specific sites:

site compiled PTCs actual PTCs
google.com 0.24% 4.14%
facebook.com 2.14% 4.93%
youtube.com 0.06% 0.90%.
wikipedia.org 0.90% 3.54%
amazon.com 0.12% 1.39%
ebay.com 0.19% 6.08%
paypal.com 0.66% 0.19%
apple.com 0.20% 3.30%

For sake of discussion, let's summarize this data with about .4% of calls in javascript source in the wild will be PTC's. At runtime, these paths seem to be more prominent and account for ~5% of actual paths.
There are several things this data says to me:

  1. Very little code, less than .4%, are PTCs.
  2. PTCs occur along paths that are somewhat common as those paths are 10x likely to get executed.
  3. Given items 1. and 2., it would seem to me that PTCs exist in some common javascript libraries. If this is true, then the debugging and telemetry issue are much more localized.
  4. Performance concerns are not as much of an issue given that only 5% of actual calls are PTCs. If a browser's PTC implementation is 10% slower that a standard call, that will only have a .5% impact overall on the typical webpage.
  5. The STC tax discussed earlier appears to have a higher price in that we will require programmers to opt in to tail calls to mitigate an issue in .4% of the current source. Seems like a high price to pay for an arguable small problem. Even considering the facebook.com data, the source prevalence of PTC's for that site is ~2%.
Contributor

msaboff commented May 5, 2016

Since much of this discussion is based on assumptions with very little data, I decided to instrument JSC and see what happens on real webpages. I added compile time and runtime counters, basically to determine what percent of calls end up as PTC at compile time and then determine what percent of actual calls are PTC versus normal calls. The runtime result fit my gut instinct at ~5%. The percent of calls that get compiled to PTC surprised me on the low side, typically much less than 1%. I did not include true constructor calls in the data.

I performed 2 broad tests, first loading the top ~1000 Alexa sites, and then navigating specific sites that are high on the Alexa list that I could access without an account or with my own account. First the Alexa data, with raw numbers:

At compile time there were 6,683,375 calls of which 24,393 where PTCs (0.36%). While executing, 179,610,729 calls were made of which 8,396,396 where PTCs (4.67%).

Here is summary data for the specific sites:

site compiled PTCs actual PTCs
google.com 0.24% 4.14%
facebook.com 2.14% 4.93%
youtube.com 0.06% 0.90%.
wikipedia.org 0.90% 3.54%
amazon.com 0.12% 1.39%
ebay.com 0.19% 6.08%
paypal.com 0.66% 0.19%
apple.com 0.20% 3.30%

For sake of discussion, let's summarize this data with about .4% of calls in javascript source in the wild will be PTC's. At runtime, these paths seem to be more prominent and account for ~5% of actual paths.
There are several things this data says to me:

  1. Very little code, less than .4%, are PTCs.
  2. PTCs occur along paths that are somewhat common as those paths are 10x likely to get executed.
  3. Given items 1. and 2., it would seem to me that PTCs exist in some common javascript libraries. If this is true, then the debugging and telemetry issue are much more localized.
  4. Performance concerns are not as much of an issue given that only 5% of actual calls are PTCs. If a browser's PTC implementation is 10% slower that a standard call, that will only have a .5% impact overall on the typical webpage.
  5. The STC tax discussed earlier appears to have a higher price in that we will require programmers to opt in to tail calls to mitigate an issue in .4% of the current source. Seems like a high price to pay for an arguable small problem. Even considering the facebook.com data, the source prevalence of PTC's for that site is ~2%.
@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan May 5, 2016

Member

@msaboff Thanks for collecting this data. Interesting to see that less frequently called code does fewer tail calls.

4+% of runtime calls sounds like plenty of calls to me, and I would be concerned about losing nearly 1 in 20 stack frames for debugging. This seems to confirm my fears.

Member

littledan commented May 5, 2016

@msaboff Thanks for collecting this data. Interesting to see that less frequently called code does fewer tail calls.

4+% of runtime calls sounds like plenty of calls to me, and I would be concerned about losing nearly 1 in 20 stack frames for debugging. This seems to confirm my fears.

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan May 5, 2016

Member

About point 5., I don't think any of the existing calls should be changed to make a tail call. Instead, STC should be used in new code which wants to take advantage of a feature which was not previously present at all, which is to allow tail-recursive loops without very low restrictions on the number of the number of iterations. STC and PTC are not performance features; it is important that we document this for users.

Member

littledan commented May 5, 2016

About point 5., I don't think any of the existing calls should be changed to make a tail call. Instead, STC should be used in new code which wants to take advantage of a feature which was not previously present at all, which is to allow tail-recursive loops without very low restrictions on the number of the number of iterations. STC and PTC are not performance features; it is important that we document this for users.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 5, 2016

Contributor

About point 5., I don't think any of the existing calls should be changed to make a tail call. Instead, STC should be used in new code which wants to take advantage of a feature which was not previously present at all, which is to allow tail-recursive loops without very low restrictions on the number of the number of iterations. STC and PTC are not performance features; it is important that we document this for users.

My point is that because there are concerns that PTCs will cause issues, it is suggested that we introduce STCs. I have no expectation that programmers will go back and add the appropriate syntax for STC at any of the current PTC sites. In fact given that they'll most likely want their code to run on older browsers, I expect that number to be close to 0. If we abandon PTC in favor of STC though, every programmer that wants to use tail calls must add whatever syntax STC requires specifically because we are worried about the .4% of PTCs in source code today. That is a high future tax for an arguable a small problem today.

Contributor

msaboff commented May 5, 2016

About point 5., I don't think any of the existing calls should be changed to make a tail call. Instead, STC should be used in new code which wants to take advantage of a feature which was not previously present at all, which is to allow tail-recursive loops without very low restrictions on the number of the number of iterations. STC and PTC are not performance features; it is important that we document this for users.

My point is that because there are concerns that PTCs will cause issues, it is suggested that we introduce STCs. I have no expectation that programmers will go back and add the appropriate syntax for STC at any of the current PTC sites. In fact given that they'll most likely want their code to run on older browsers, I expect that number to be close to 0. If we abandon PTC in favor of STC though, every programmer that wants to use tail calls must add whatever syntax STC requires specifically because we are worried about the .4% of PTCs in source code today. That is a high future tax for an arguable a small problem today.

@jeffmo

This comment has been minimized.

Show comment
Hide comment
@jeffmo

jeffmo May 5, 2016

Member

I have no expectation that programmers will go back and add the appropriate syntax for STC at any of the current PTC sites

I think this is a source of the disagreement: The notion that any calls that exist in tail position today will necessarily benefit from being picked up as a PTC tomorrow.

I suspect proponents of the STC proposal would argue that, because no code today needs PTC, there is little benefit (and clearly a change in semantics) to retroactively instituting it for that code. Moreover, the basis of the STC proposal seems to be that tail calls are only meant to be intentional and shouldn't be accidental -- thus retrofitting the behavior into existing code is really a non-goal.

Member

jeffmo commented May 5, 2016

I have no expectation that programmers will go back and add the appropriate syntax for STC at any of the current PTC sites

I think this is a source of the disagreement: The notion that any calls that exist in tail position today will necessarily benefit from being picked up as a PTC tomorrow.

I suspect proponents of the STC proposal would argue that, because no code today needs PTC, there is little benefit (and clearly a change in semantics) to retroactively instituting it for that code. Moreover, the basis of the STC proposal seems to be that tail calls are only meant to be intentional and shouldn't be accidental -- thus retrofitting the behavior into existing code is really a non-goal.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 6, 2016

Contributor

After discussion with colleagues and some reflection, I'd like to add a couple more points that I believe are relevant to this thread.

  1. Given the data says there is a 10x likelihood that a current PTC gets called compared to a standard call, we suspect that the majority of those PTCs are commonly called wrapper or forwarding functions.
  2. Typically telemetry systems match the top one to few stack frames, and only rarely if ever depend on the rest of the stack for anything, since a bug in a function can be triggered by multiple different call sites. Are there any known examples of telemetry systems that depend on matching the whole call stack?
  3. Telemetry systems already bucket by browser since some errors are particular to specific browsers, some expected API invocations differ between browsers, and error.stack formatting differs across browsers. So, it doesn’t matter if new browsers elide frames that old browsers included — telemetry systems will be self-consistent within browsers versions as they always have needed to be.

Taken together the data would suggest that the impact of current in the wild PTCs on telemetry systems would be quite low.

Contributor

msaboff commented May 6, 2016

After discussion with colleagues and some reflection, I'd like to add a couple more points that I believe are relevant to this thread.

  1. Given the data says there is a 10x likelihood that a current PTC gets called compared to a standard call, we suspect that the majority of those PTCs are commonly called wrapper or forwarding functions.
  2. Typically telemetry systems match the top one to few stack frames, and only rarely if ever depend on the rest of the stack for anything, since a bug in a function can be triggered by multiple different call sites. Are there any known examples of telemetry systems that depend on matching the whole call stack?
  3. Telemetry systems already bucket by browser since some errors are particular to specific browsers, some expected API invocations differ between browsers, and error.stack formatting differs across browsers. So, it doesn’t matter if new browsers elide frames that old browsers included — telemetry systems will be self-consistent within browsers versions as they always have needed to be.

Taken together the data would suggest that the impact of current in the wild PTCs on telemetry systems would be quite low.

@concavelenz

This comment has been minimized.

Show comment
Hide comment
@concavelenz

concavelenz May 6, 2016

RE: 1. PTC doesn't dictate that the method is trivial.

A method could easily end with trivial check and the interesting method would be lost.

return ThrowIfNullOrUndefined(result);

RE: 2. The interesting data can be arbitrarily deep. Often we see 4 or 5 frames of logging infrastructure.

RE: 3. That different browser report different frames isn't particularly important, but that interesting frames are lost is the issue. PTC requires that you "get lucky" to preserve the correct stack frames.

RE: 1. PTC doesn't dictate that the method is trivial.

A method could easily end with trivial check and the interesting method would be lost.

return ThrowIfNullOrUndefined(result);

RE: 2. The interesting data can be arbitrarily deep. Often we see 4 or 5 frames of logging infrastructure.

RE: 3. That different browser report different frames isn't particularly important, but that interesting frames are lost is the issue. PTC requires that you "get lucky" to preserve the correct stack frames.

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 6, 2016

Contributor

RE: 1. PTC doesn't dictate that the method is trivial.

Of course. I wrote that I speculated that the PTC calling methods are wrappers.

RE: 3. That different browser report different frames isn't particularly important, but that interesting frames are lost is the issue. PTC requires that you "get lucky" to preserve the correct stack frames.

Since the frames lost are PTC callers, they don't contain the reporting code, but are on the path to the reporting code. IF they are wrapper functions, losing those frames from the stack trace is a very small lose of information.

Contributor

msaboff commented May 6, 2016

RE: 1. PTC doesn't dictate that the method is trivial.

Of course. I wrote that I speculated that the PTC calling methods are wrappers.

RE: 3. That different browser report different frames isn't particularly important, but that interesting frames are lost is the issue. PTC requires that you "get lucky" to preserve the correct stack frames.

Since the frames lost are PTC callers, they don't contain the reporting code, but are on the path to the reporting code. IF they are wrapper functions, losing those frames from the stack trace is a very small lose of information.

@concavelenz

This comment has been minimized.

Show comment
Hide comment
@concavelenz

concavelenz May 10, 2016

I meant to ask, if you are only count "strict" code where PTC is active or
if you are counting non-strict code.

On Fri, May 6, 2016 at 3:26 PM, Michael Saboff notifications@github.com
wrote:

RE: 1. PTC doesn't dictate that the method is trivial.

Of course. I wrote that I speculated that the PTC calling methods are
wrappers.

Right, and I'm stating I don't believe there is any reason to believe that.

RE: 3. That different browser report different frames isn't particularly
important, but that interesting frames are lost is the issue. PTC requires
that you "get lucky" to preserve the correct stack frames.

Since the frames lost are PTC callers, they don't contain the reporting
code, but are on the path to the reporting code. IF they are wrapper
functions, losing those frames from the stack trace is a very small lose of
information.

I think we are using different meanings of "reporting". Here I mean the
path to the function that is causing the stack trace to be collected, which
may not be source of the "error" but just some bit of the logging
infrastructure:

function report(msg) {
var record = createReportRecord(msg); // add a stack trace
sendReport(record);
}

function doStuff() {
...
if (...) {
...
return result;
}
report("failed")
}


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#535 (comment)

I meant to ask, if you are only count "strict" code where PTC is active or
if you are counting non-strict code.

On Fri, May 6, 2016 at 3:26 PM, Michael Saboff notifications@github.com
wrote:

RE: 1. PTC doesn't dictate that the method is trivial.

Of course. I wrote that I speculated that the PTC calling methods are
wrappers.

Right, and I'm stating I don't believe there is any reason to believe that.

RE: 3. That different browser report different frames isn't particularly
important, but that interesting frames are lost is the issue. PTC requires
that you "get lucky" to preserve the correct stack frames.

Since the frames lost are PTC callers, they don't contain the reporting
code, but are on the path to the reporting code. IF they are wrapper
functions, losing those frames from the stack trace is a very small lose of
information.

I think we are using different meanings of "reporting". Here I mean the
path to the function that is causing the stack trace to be collected, which
may not be source of the "error" but just some bit of the logging
infrastructure:

function report(msg) {
var record = createReportRecord(msg); // add a stack trace
sendReport(record);
}

function doStuff() {
...
if (...) {
...
return result;
}
report("failed")
}


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#535 (comment)

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 10, 2016

Contributor

I meant to ask, if you are only count "strict" code where PTC is active or
if you are counting non-strict code.

I counted all code. I wanted to measure how common PTC are across all web pages.

As far as likelihood of a PTC being elided from a stack trace that gets reported via telemetry, you and I are both speculating. Maybe we can agree that ~5% of frames will not appear in the stack trace. As far as what those elided functions look like, we don't know without further investigation.

Contributor

msaboff commented May 10, 2016

I meant to ask, if you are only count "strict" code where PTC is active or
if you are counting non-strict code.

I counted all code. I wanted to measure how common PTC are across all web pages.

As far as likelihood of a PTC being elided from a stack trace that gets reported via telemetry, you and I are both speculating. Maybe we can agree that ~5% of frames will not appear in the stack trace. As far as what those elided functions look like, we don't know without further investigation.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson May 10, 2016

Member

@msaboff Do you know what percent of calls are syntactically tail calls but not only due to containing code being sloppy?

Member

bterlson commented May 10, 2016

@msaboff Do you know what percent of calls are syntactically tail calls but not only due to containing code being sloppy?

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 10, 2016

Contributor

Do you know what percent of calls are syntactically tail calls but not only due to containing code being sloppy?

I do not. I put my compile counters at the point where the parser is issuing a call byte code, which is after where we've determined whether or not it is a PTC and for your question WHY we determined it is or isn't a PTC.

Contributor

msaboff commented May 10, 2016

Do you know what percent of calls are syntactically tail calls but not only due to containing code being sloppy?

I do not. I put my compile counters at the point where the parser is issuing a call byte code, which is after where we've determined whether or not it is a PTC and for your question WHY we determined it is or isn't a PTC.

@littledan

This comment has been minimized.

Show comment
Hide comment
@littledan

littledan May 10, 2016

Member

Seems like we might expect this number to increase a bit over time as strict mode usage increases.

Member

littledan commented May 10, 2016

Seems like we might expect this number to increase a bit over time as strict mode usage increases.

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson May 10, 2016

Member

Either a bit or a lot, maybe, depending on how prevalent strict mode is today. I haven't seen numbers for a couple years, but last I checked sloppy was by far the most prevalent mode.

Member

bterlson commented May 10, 2016

Either a bit or a lot, maybe, depending on how prevalent strict mode is today. I haven't seen numbers for a couple years, but last I checked sloppy was by far the most prevalent mode.

@claudepache

This comment has been minimized.

Show comment
Hide comment
@claudepache

claudepache May 11, 2016

Contributor

There is a fear that useful debugging info (stack trace report) would be degraded with PTC. The fear is valid, but pushing back PTC as possible remedy looks backwards. Since the issue is with stack trace, not with PTC per se, stack trace should be improved rather than PTC degraded.

For example, I imagine that a given stack frame could keep track, for debugging purpose, not only of the function that is currently using the frame, but also of the first function that used it (the one whose call induced the creation of the frame), and of the number of PTC that has occurred for that frame. Then, experience would show if more debugging info is needed.

Contributor

claudepache commented May 11, 2016

There is a fear that useful debugging info (stack trace report) would be degraded with PTC. The fear is valid, but pushing back PTC as possible remedy looks backwards. Since the issue is with stack trace, not with PTC per se, stack trace should be improved rather than PTC degraded.

For example, I imagine that a given stack frame could keep track, for debugging purpose, not only of the function that is currently using the frame, but also of the first function that used it (the one whose call induced the creation of the frame), and of the number of PTC that has occurred for that frame. Then, experience would show if more debugging info is needed.

@rossberg

This comment has been minimized.

Show comment
Hide comment
@rossberg

rossberg May 11, 2016

Member

@claudepache, TCE doesn't mean reusing stack frames, if that's what you're thinking. That wouldn't be possible in most cases, because functions differ in their number of arguments, of local variables, calling conventions, or even general stack frame layouts, e.g. in the presence of different optimisation tiers. You can even tail-call functions that are not JavaScript at all, and vice versa.

What a tail call generally does is removing the current stack frame before it performs an ordinary call. The reuse you imagine is a possible optimisation in only a few special cases (mostly self recursion).

Member

rossberg commented May 11, 2016

@claudepache, TCE doesn't mean reusing stack frames, if that's what you're thinking. That wouldn't be possible in most cases, because functions differ in their number of arguments, of local variables, calling conventions, or even general stack frame layouts, e.g. in the presence of different optimisation tiers. You can even tail-call functions that are not JavaScript at all, and vice versa.

What a tail call generally does is removing the current stack frame before it performs an ordinary call. The reuse you imagine is a possible optimisation in only a few special cases (mostly self recursion).

@bterlson

This comment has been minimized.

Show comment
Hide comment
@bterlson

bterlson May 11, 2016

Member

I found the data I alluded to above (see my presentation): http://wiki.ecmascript.org/doku.php?id=meetings:meeting_jan_29_2013. In early 2013 I found that only ~4% of sites contained some strict code. I suspect this has increased lately but I'm not sure how much.

@msaboff it would be really helpful to know what percent of strict calls are also tail calls if you can find out somehow :)

Member

bterlson commented May 11, 2016

I found the data I alluded to above (see my presentation): http://wiki.ecmascript.org/doku.php?id=meetings:meeting_jan_29_2013. In early 2013 I found that only ~4% of sites contained some strict code. I suspect this has increased lately but I'm not sure how much.

@msaboff it would be really helpful to know what percent of strict calls are also tail calls if you can find out somehow :)

@saambarati

This comment has been minimized.

Show comment
Hide comment
@saambarati

saambarati May 13, 2016

@claudepache @rossberg-chromium Regardless of the mechanism used to accomplish this, there are methods for keeping around the interesting bits of the stack in a world with tail calls. I.e, keeping the top X frames when the debugger is enabled.
This will solve almost every interesting debugging scenario in a world with tail calls:
-- Your program is not written with PTC in mind and is not knowingly using PTC.
This means that in any given stack trace, there will be very few frames that would have
been elided because of tail calls. This means that smart debugger integration will show
all those frames that would have been elided because it will almost always be less than X.
-- Your program is written to take advantage of PTC and will have many loops written using
recursion. In such a scenario, the debugger will show you the top X tail called frames (along
with the rest of the not tail-call elided frames). This is almost always a good solution because
the most interesting frame is the top frame. All other X - 1 frames are just nice to have. And sometimes,
having these frames will just cause clutter. It's not obvious that a program written to utilize PTC
that has a loop written as recursion will always want to see X iterations of the loop in the call
stack. It may even be beneficial to have the debugger intelligently compact frames that are
obviously part of a tail recursive loop.

@claudepache @rossberg-chromium Regardless of the mechanism used to accomplish this, there are methods for keeping around the interesting bits of the stack in a world with tail calls. I.e, keeping the top X frames when the debugger is enabled.
This will solve almost every interesting debugging scenario in a world with tail calls:
-- Your program is not written with PTC in mind and is not knowingly using PTC.
This means that in any given stack trace, there will be very few frames that would have
been elided because of tail calls. This means that smart debugger integration will show
all those frames that would have been elided because it will almost always be less than X.
-- Your program is written to take advantage of PTC and will have many loops written using
recursion. In such a scenario, the debugger will show you the top X tail called frames (along
with the rest of the not tail-call elided frames). This is almost always a good solution because
the most interesting frame is the top frame. All other X - 1 frames are just nice to have. And sometimes,
having these frames will just cause clutter. It's not obvious that a program written to utilize PTC
that has a loop written as recursion will always want to see X iterations of the loop in the call
stack. It may even be beneficial to have the debugger intelligently compact frames that are
obviously part of a tail recursive loop.

@ljharb

This comment has been minimized.

Show comment
Hide comment
@ljharb

ljharb May 13, 2016

Member

@saambarati what about the cases where one wants to introspect the stack frames at runtime, sans any debugger being present?

Member

ljharb commented May 13, 2016

@saambarati what about the cases where one wants to introspect the stack frames at runtime, sans any debugger being present?

@msaboff

This comment has been minimized.

Show comment
Hide comment
@msaboff

msaboff May 17, 2016

Contributor

it would be really helpful to know what percent of strict calls are also tail calls if you can find out somehow :)

@bterlson, I found the time to collect some "strict mode call" numbers. I added another counter at compile time. If we generate a "call" byte code and we are currently in strict mode, I bump the new counter. Again I ran the top 1100 Alexa sites and collected the data. I then went to a smaller set of individual pages, navigated around them and collected data for each of those sites.

For the Alexa tests, at compile time there were 7,703778 calls of which 28,906 were PTCs (0.38%). 716,931 of all calls where found in strict code (9.31% of all calls are strict and 4.03% of strict calls are PTC). While executing, 161,758,015 calls were made of which 8,194,931 where PTCs (5.07%).

For the individual sites I navigated, my process was less scientific. I didn't record how I navigated around each site the first time, so I likely hit different paths this time. Here is summary data for the specific sites:

site compiled PTCs compiled strict strict that are PTC actual PTCs
google.com 0.13% 9.31% 6.58% 3.91%
facebook.com 2.01% 41.07% 4.90% 4.86%
ebay.com 0.21% 6.59% 3.13% 4.93%
paypal.com 0.53% 19.93% 2.68% 2.46%
apple.com 0.26% 6.18% 4.25% 3.90%

Facebook and PayPal for the win on using strict mode!

It is interesting to note that in most cases the incidence of PTC in strict source is fairly close to the percent of actually called PTC. For the Alexa run, 4% of compiled strict calls are PTC while at run time 5% of calls are PTC.

Contributor

msaboff commented May 17, 2016

it would be really helpful to know what percent of strict calls are also tail calls if you can find out somehow :)

@bterlson, I found the time to collect some "strict mode call" numbers. I added another counter at compile time. If we generate a "call" byte code and we are currently in strict mode, I bump the new counter. Again I ran the top 1100 Alexa sites and collected the data. I then went to a smaller set of individual pages, navigated around them and collected data for each of those sites.

For the Alexa tests, at compile time there were 7,703778 calls of which 28,906 were PTCs (0.38%). 716,931 of all calls where found in strict code (9.31% of all calls are strict and 4.03% of strict calls are PTC). While executing, 161,758,015 calls were made of which 8,194,931 where PTCs (5.07%).

For the individual sites I navigated, my process was less scientific. I didn't record how I navigated around each site the first time, so I likely hit different paths this time. Here is summary data for the specific sites:

site compiled PTCs compiled strict strict that are PTC actual PTCs
google.com 0.13% 9.31% 6.58% 3.91%
facebook.com 2.01% 41.07% 4.90% 4.86%
ebay.com 0.21% 6.59% 3.13% 4.93%
paypal.com 0.53% 19.93% 2.68% 2.46%
apple.com 0.26% 6.18% 4.25% 3.90%

Facebook and PayPal for the win on using strict mode!

It is interesting to note that in most cases the incidence of PTC in strict source is fairly close to the percent of actually called PTC. For the Alexa run, 4% of compiled strict calls are PTC while at run time 5% of calls are PTC.

@concavelenz

This comment has been minimized.

Show comment
Hide comment
@concavelenz

concavelenz May 19, 2016

Thanks for getting some numbers regarding strict mode. But I'm not really
sure what conclusions I can draw from these updated numbers.

As an FYI, plus.google.com (not classic) and photos.google.com should be
almost entirely strict. In contrast, I'm surprised google.com has any
strict code.
On May 17, 2016 2:34 PM, "Michael Saboff" notifications@github.com wrote:

it would be really helpful to know what percent of strict calls are also
tail calls if you can find out somehow :)

@bterlson https://github.com/bterlson, I found the time to collect some
"strict mode call" numbers. I added another counter at compile time. If we
generate a "call" byte code and we are currently in strict mode, I bump the
new counter. Again I ran the top 1100 Alexa sites and collected the data. I
then went to a smaller set of individual pages, navigated around them and
collected data for each of those sites.

For the Alexa tests, at compile time there were 7,703778 calls of which
28,906 were PTCs (0.38%). 716,931 of all calls where found in strict code
(9.31% of all calls are strict and 4.03% of strict calls are PTC). While
executing, 161,758,015 calls were made of which 8,194,931 where PTCs
(5.07%).

For the individual sites I navigated, my process was less scientific. I
didn't record how I navigated around each site the first time, so I likely
hit different paths this time. Here is summary data for the specific sites:
site compiled PTCs compiled strict strict that are PTC actual PTCs
google.com 0.13% 9.31% 6.58% 3.91%
facebook.com 2.01% 41.07% 4.90% 4.86%
ebay.com 0.21% 6.59% 3.13% 4.93%
paypal.com 0.53% 19.93% 2.68% 2.46%
apple.com 0.26% 6.18% 4.25% 3.90%

Facebook and PayPal for the win on using strict mode!

It is interesting to note that in most cases the incidence of PTC in strict
source is fairly close to the percent of actually called PTC. For the Alexa
run, 4% of compiled strict calls are PTC while at run time 5% of calls are
PTC.


You are receiving this because you commented.

Reply to this email directly or view it on GitHub
#535 (comment)

Thanks for getting some numbers regarding strict mode. But I'm not really
sure what conclusions I can draw from these updated numbers.

As an FYI, plus.google.com (not classic) and photos.google.com should be
almost entirely strict. In contrast, I'm surprised google.com has any
strict code.
On May 17, 2016 2:34 PM, "Michael Saboff" notifications@github.com wrote:

it would be really helpful to know what percent of strict calls are also
tail calls if you can find out somehow :)

@bterlson https://github.com/bterlson, I found the time to collect some
"strict mode call" numbers. I added another counter at compile time. If we
generate a "call" byte code and we are currently in strict mode, I bump the
new counter. Again I ran the top 1100 Alexa sites and collected the data. I
then went to a smaller set of individual pages, navigated around them and
collected data for each of those sites.

For the Alexa tests, at compile time there were 7,703778 calls of which
28,906 were PTCs (0.38%). 716,931 of all calls where found in strict code
(9.31% of all calls are strict and 4.03% of strict calls are PTC). While
executing, 161,758,015 calls were made of which 8,194,931 where PTCs
(5.07%).

For the individual sites I navigated, my process was less scientific. I
didn't record how I navigated around each site the first time, so I likely
hit different paths this time. Here is summary data for the specific sites:
site compiled PTCs compiled strict strict that are PTC actual PTCs
google.com 0.13% 9.31% 6.58% 3.91%
facebook.com 2.01% 41.07% 4.90% 4.86%
ebay.com 0.21% 6.59% 3.13% 4.93%
paypal.com 0.53% 19.93% 2.68% 2.46%
apple.com 0.26% 6.18% 4.25% 3.90%

Facebook and PayPal for the win on using strict mode!

It is interesting to note that in most cases the incidence of PTC in strict
source is fairly close to the percent of actually called PTC. For the Alexa
run, 4% of compiled strict calls are PTC while at run time 5% of calls are
PTC.


You are receiving this because you commented.

Reply to this email directly or view it on GitHub
#535 (comment)

@hax

This comment has been minimized.

Show comment
Hide comment
@hax

hax Dec 12, 2016

Any conclusion?

hax commented Dec 12, 2016

Any conclusion?

@YurySolovyov

This comment has been minimized.

Show comment
Hide comment
@YurySolovyov

YurySolovyov Nov 15, 2017

With Firefox launches like Electrolysis and Quantum, are there any changes with respect to Tail Calls ?
Asking because I remember sandbox or process model as the reason FF can't have Tail Calls

With Firefox launches like Electrolysis and Quantum, are there any changes with respect to Tail Calls ?
Asking because I remember sandbox or process model as the reason FF can't have Tail Calls

@hashseed

This comment has been minimized.

Show comment
Hide comment
@hashseed

hashseed Nov 15, 2017

iiuc none of these affect SpiderMonkey, which iirc requires stack frames for security checks.

iiuc none of these affect SpiderMonkey, which iirc requires stack frames for security checks.

@enright

This comment has been minimized.

Show comment
Hide comment
@enright

enright Jan 17, 2018

I write functional ES6 code that depends on proper tail call implementation according to the spec. Use my code in Node v6 with harmony flag...works fine. Use my code in Node v8...blows out the stack. This is stupid.

Why in the world should I have to put up with non-conformance? Are you kidding me?

enright commented Jan 17, 2018

I write functional ES6 code that depends on proper tail call implementation according to the spec. Use my code in Node v6 with harmony flag...works fine. Use my code in Node v8...blows out the stack. This is stupid.

Why in the world should I have to put up with non-conformance? Are you kidding me?

@glathoud

This comment has been minimized.

Show comment
Hide comment
@glathoud

glathoud Jun 25, 2018

Here is one possibility for developers to use fast tail calls today, without needing extra keywords in JavaScript: https://github.com/glathoud/fext

Here is one possibility for developers to use fast tail calls today, without needing extra keywords in JavaScript: https://github.com/glathoud/fext

@glathoud

This comment has been minimized.

Show comment
Hide comment
@glathoud

glathoud Jun 28, 2018

I do not see as spam the fact that one can generate optimized code using today's standard JavaScript.

I do not see as spam the fact that one can generate optimized code using today's standard JavaScript.

@leobalter

This comment has been minimized.

Show comment
Hide comment
@leobalter

leobalter Jun 28, 2018

Member

@glathoud I don't know what flagged this as spam but this library - despite being interesting probably useful - is not on topic for what should be discussed here. The topic holds concerns for implementing Tail Calls natively as in the language specs, answering to another topic proposing a syntactical Tail Call grammar.

Member

leobalter commented Jun 28, 2018

@glathoud I don't know what flagged this as spam but this library - despite being interesting probably useful - is not on topic for what should be discussed here. The topic holds concerns for implementing Tail Calls natively as in the language specs, answering to another topic proposing a syntactical Tail Call grammar.

@glathoud

This comment has been minimized.

Show comment
Hide comment
@glathoud

glathoud Jun 29, 2018

@leobalter At first sight, yes, off-topic.

But whoever tries to implement the whole complexity of mutual tail recursion optimization in a dynamic language - in a broad sense - like JavaScript might well stumble upon a few issues. My 2 cents :)

@leobalter At first sight, yes, off-topic.

But whoever tries to implement the whole complexity of mutual tail recursion optimization in a dynamic language - in a broad sense - like JavaScript might well stumble upon a few issues. My 2 cents :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment