-
Notifications
You must be signed in to change notification settings - Fork 27
Should errors be a prototype accessor that returns the value of an internal slot? #38
Comments
Is there any reason at all to do so? If I recall correctly we discussed the possibility of doing something similar with the |
That’s because match objects are normal arrays already and have no prototype; the primary precedent for own data properties (that admittedly is highly relevant) is the message property on Errors. Most things are accessors pulling from slots. |
I'd strongly be in favor to have these on the prototype. |
@bmeurer are there any concrete reasons to avoid an own property for “errors”? |
Actually, scratch my last comment, my thinking was wrong here. I thought it might be better for implementations to have a prototype getter so that the real errors can be computed lazily, and we don't need to do this weird dance that we have to do with For the |
Okay, I'm inclined to close this one then. The current spec has |
"lazily computed" isn't the bar for things being on the prototype, though. "message" is an own property, but that seems to be a rare occurrence. RegExps, for example, use slot-reading accessors in ES6+ even for things that were own properties in prior editions. |
Maybe modeling
Whether |
Given that the two consistencies being chosen between are actually:
… and the first one would cause issues for Moddable and SES (due to the so-called "override mistake"), that suggests to me that it should be an accessor. |
If |
Is there additional information on what is meant by "an override mistake"? |
@rbuckton instead of consistency with Errors' |
I have to say "own data properties with defaults on the prototype" is very weird which made the shape ( |
@ljharb When will a function instance use name/length on prototype? |
@hax all anonymous functions lack a |
But |
It seems after that PR land, Error's |
Not sure what you mean by unstable; but that PR doesn’t change my list above. |
I mean |
In that case, after the PR lands, function |
I'm confused, it seems the PR never touch |
It won't; that's its current behavior (the prototype property is there, but shadowed by the own property on an instance) |
Closes #38. Per 2019.10.03 TC39 consensus; once this PR is approved and merged, the proposal has stage 3.
@ljharb |
@caridy said
OMG @caridy I could not disagree more with what you said in this quote. However, I suspect that I may not disagree with what you meant. ES3 had crazy communications channels, such as An example of primordial hidden mutable state that we missed in ES5 is Another example is the legacy RegExp statics like On the particular issue here, the slogan to remember is "If it is not fresh or frozen, then it is rotten". The array of error objects in the aggregate error is fresh. It is indeed consistent with the general language style to have this be a fresh mutable plain array of mutable error objects, just like the containing aggregate error object is mutable. The key thing is that it is fresh. Any fresh mutable object is a communications channel among those who share direct access to it. But the fact that it is fresh means that this sharing relationship must already exist, and must already constitute a communications channel --- hopefully a legitimately authorized one. The array only needs to be as fresh as the aggregate error. Unlike the current accessor spec text, the array need not be fresh on every access. |
Writing this down also helps highlight why storing this array in an exotic internal slot is more dangerous than most internal slots that are already in the spec. Consider all of the following:
Every single one of those above, even including the ones we've worked so hard to fix, leak only information. The proposed internal slot for aggregate errors provide access to first class mutable objects --- the array of component errors. Even if the array is frozen, the component errors it hold presumably are not. The only other place I can think of where shared access to a first class object leaks though a hidden channel is templates, via the template cache. For this one case, we purposefully violated the normal ES style by specifying that this template consists of transitively frozen arrays of strings. Thus no mutable state and no communications channel. I am not saying that, for example, membrane security would not be able to cope with this new internal slot, if we did go that way. But it is indeed a much harder case to think about than all of the bullets listed above. My conclusion is that |
@erights: Probably to strong wording from my side, should have been more specific. We are in agreement there for sure.
I also agree with that conclusion. |
It seems to me, that this issue should be discussed at March TC39 meeting. @mathiasbynens WDYT? Do you have time to present an update on |
I'd be happy to present this at a future TC39 meeting but it would be ideal to come to agreement in this thread beforehand if at all possible, to reduce plenary discussion time. @ljharb, what do you think? Would you be okay with this changing back to an own data property?
I'm hearing echoes of the 2019-10-02 TC39 meeting:
|
My reply in the notes remains applicable imo:
I vastly prioritize consistency with the rest of the spec here. Own properties are rare (and I think, mostly all legacy), and we should keep them that way. |
For the accessors you're talking about, the value they're reflecting is otherwise observable, either by behavior or in other properties. That is not the case here. I do not think we need to copy that decision when the logic which justified it does not apply. Contrast, for example, the decidedly non-legacy Symbol.toStringTag, which is a data property and which makes sense as a data property because it does not reflect any otherwise-accessible state. |
It's a data property on the prototype - not an own property - that contains a primitive; it's hardly similar to this case. |
The accessors you're talking about almost all contain primitives as well (and, again, much more importantly, they reflect values which are otherwise observable). They are also hardly similar to this case. |
For purposes of this thread, I refer to an exotic internal slot that proxies don't know about, like that on My objection isn't to adding an accessor. My objection is to adding a new exotic internal slot, Today, all standard exotic internal slots only contain data. Shared access to get or set the slot only leaks information. Shared access does not imply the ability to communicate direct references to objects. Even if it didn't violate this invariant, I am resistant to adding new exotic internal slots. If a proposed exotic internal slot can only hold data, then my resistance could yield in the face of a compelling enough need. The error stack proposal, for example, adds an internal slot to all error instances, so it is much more pervasive than what is proposed here. But the new internal error slot contains only data. The case for the error slot is compelling enough that I am in favor of it. (Ironically, @ljharb and I are its co-champions.) In the case proposed here, the own-property alternative demonstrates there is no compelling enough need. Given that it also conveys direct access to objects, we simply should not add it. As to following spec precedent, that cuts both ways. Nothing in the existing spec violates this invariant, so precedent says not to violate it here either. Let's do own property. It solves the problem without creating new problems. |
@ljharb wrote:
This came as a bit of a surprise to me and I wonder if the committee at large agrees it's the case. I'm OK with either outcome here, but Mozilla's reluctant to ship this feature without TC39 approving a direction. |
I remain opposed to an exotic internal slot holding objects. There is no
precedent and it is dangerous.
On Fri, May 22, 2020 at 7:01 AM Jason Orendorff ***@***.***> wrote:
@ljharb <https://github.com/ljharb> wrote:
I vastly prioritize consistency with the rest of the spec here. Own
properties are rare (and I think, mostly all legacy), and we should keep
them that way.
This came as a bit of a surprise to me and I wonder if the committee at
large agrees it's the case.
I'm OK with either outcome here, but Mozilla's reluctant to ship this
feature without TC39 approving a direction.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#38 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACC3TCZFEQHKY6LFGCWQXTRS2ATZANCNFSM4I2OBKEQ>
.
--
Cheers,
--MarkM
|
@erights is it dangerous only because it's on the prototype? iow, if it were an own accessor that returned the same mutable object every time from an internal slot (not that i'm advocating for this), would that be OK? If not, can you help me understand why not? |
Would the same behavior be described by saying that the accessor's getter function encapsulates the object, so the same getter always returns the same object regardless of how it is called? The primordial heap has none of these getters, since it has no error instances? If both are true, it is likely safe. But I'm glad you're not advocating this position ;) |
I've thought some more about this, and had some more discussion with a few folks. I feel very strongly that the current inability to robustly distinguish Error types is a mistake. My hope here was that AggregateError would not expand/worsen/repeat that mistake. However, unless we plan to add many more than 6 additional new error types, what we'd end up with is two "clouds" of errors: the majority and legacy ones, that do not properly distinguish between themselves; and the new ones (which would likely just be AggregateError). That inconsistency doesn't seem worth the very minor victory of not repeating a mistake. As such, I'll withdraw my objection to changing |
For that goal, I am currently in the vicinity of working on the error stack shim, with expectation of getting back to our error stack proposal. That does add a new internal slot to all error objects, which would enable one to reliably distinguish errors from everything else, but not distinguish between types of errors. I remember this was one of your motivations for co-championing it. As always, I am reluctant to introduce a new internal slot, but I am in favor of this one. This slot does have the same problems that the existing exotic internal slots do. So what's different? Like the internal slot on Date and every other exotic internal slot, this one reveals only data. It cannot be used to hide and convey an object reference. That's why I am more relaxed about it than the one we just avoided (whew!) on AggregateError. Thank you! |
@erights I don't object to the conclusion here, but aren't there a lot of internal slots that can be used to pass mutable JS state? I'm thinking of slots like obj.[[Prototype]], fun.[[Environment]], method.[[HomeObject]], boundFn.[[BoundArguments]], typedArr.[[ViewedArrayBuffer]], moduleNamespace.[[Module]].[[Realm]], proxy.[[ProxyHandler]], and so on. The DOM also seems to have a lot of similar slots. Asking because iterator helpers may end up being specified as new kinds of |
I'd like to have a bit of a broader discussion here before concluding that, in general, we wouldn't have internal slots with objects in them. I'm OK with this applying to errors for reasons specific to the conventions around errors, but more skeptical about this applying to JS objects overall. I think internal slots are very normal--private fields give user code the equivalent capability--and I'm surprised by the discussion of them being "exotic". This has implications for other proposals, such as Intl.Segmenter and Temporal. I don't understand what kinds of needs are considered compelling enough, and why we're reversing course on the ES6 conventions to move from data properties towards internal slots (which feels compelling enough to me). |
In the June 2020 TC39 meeting, I tried to express that I was only comfortable settling on an own data property if this was based on some reason other than the exotic internal slot argument. I didn't fully understand if there were such other reasons; at the time, I assumed there were, but now I'm having trouble finding them. Does anyone have any pointers here? |
OK, I'm comfortable with this conclusion then. |
Conclusion of some further analysis of the "exotic internal slot hazard" noted at tc39/proposal-intl-segmenter#96 (comment) . tl;dr it doesn't seem like this should be a concern for Promise.any or AggregateError. |
Currently the proposal has “errors” as an own property that’s a normal array. Are there thoughts on making it a prototype getter that constructs an array from the contents of an internal slot?
The text was updated successfully, but these errors were encountered: