-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Concrete definitions of Object properties #1067
Comments
If this happens, we'll need to update "if value has any internal slot other than [[Prototype]] or [[Extensible]]" in the HTML Standard's StructuredSerializeInternal algorithm to also include [[Properties]] (or whatever its name becomes). |
I'm trying to understand the source of your confusion. I think it may be that you are conflating the abstract concept of the ECMAScript Object data type, as defined in clause 6.1.7 and "ordinary object" which is one of several specific concrete realization of that data type. The concepts of ordinary and exotic objects are introduced in the last paragraph of 6.1.7 and ordinary object is fully defined in 9.1. The ECMAScript data types (including Object) are defined in 6.1 from the perspective of what distinguishes them for an ECMAScript programmer. An ES programmer should not be concerned about how the semantics of these data types are specified or implemented. From an ES programmers perspective the thing that distinguishes values of the Object type from ECMAScript values of other types is the concept that an object is fundamentally a collection of properties that are created and accessed using very specific language features. The actual semantics of those language features are specified in terms of their use of the fundamental internal methods. An indirection through the internal methods is used, rather than directly associating the object semantics with the language features, to support the variations of property collection semantics that exist among the various kinds of exotic objects. But that mechanism of variation (internal methods) is just a specification device and is not relevant to the typical ES programmer (unless they are defining Proxy objects). Note in particular, that we chose to define the semantics that are applicable to all objects strictly behaviorally via the abstract definitions and invariants of the essential internal methods. We explicitly choose to avoid defining any internal slots (ie, state) that would be required for all kinds of objects to maintain. The reason is that the existence of an internal slot implies to many readers that an explicit piece of runtime state must exist and the possibility that the value of the state holder might be mutable. This may or may not be true depending upon the kind of exotic object involved. (For example, some kinds of objects might have a fixed value that is returned by [[GetPrototypeOf]]. That is preferably specified by that exotic object's behavior definition of [[GetPrototypeOf]] rather then by using a generic definition of [[GetPrototypeOf]] that access a [[Prototype]] slot. The purpose of OrdinaryGetOwnProperty is not to define that aspect of property management for all objects. It only defines it for ordinary objects (or exotic objects that are expliciltly specified as a delta on the ordinary object specification). The language of step 2 of OrdinaryGetOwnProperty should not be constructed as being circular with the abstract definition of object given in 6.1.7. Instead, it is a more concrete, specification level realization for ordinary objects of the abstract definition. I think a possible source of confusion, is that 9.1 never explicitly says that "each ordinary object maintain a set (in the mathematical sense) of its currently accessible own properties" (or perhaps Property Descriptors). The existence of such a set is implicit in the definition of the ordinary object internal methods (for example by step 2 of OrdinaryObjectGetOwnProperty) but it has to be inferred by readers of the specification. It would probably be clearer if such a set was mentioned in the introductory paragraphs of 9.1. I actually considered specify that set explicitly for ordinary object by using internal an slot whose value was an ordered List of Property Descriptors. This would be similar to how the semantics of Map and Set are specified. I didn't do it for three reasons:
So in summary:
|
This is indeed the crux of the problem. The only reason I went back to 6.1 was because I was looking for what "own properties" meant in this context and couldn't find any. Your comment generally makes sense to me. I'm going to revise my original proposal from Some of your questions/concerns:
That's really the reason why I explicitly said I wanted to be unopinionated in the underlying data structure for the [[Properties]] internal slot I proposed, and only use prose when operating on it. I don't want to prohibit any optimization that may be possible by using a more efficient data structure, or making the places where nondeterminism are currently allowed in the spec (e.g.
I agree that a List doesn't really simplify this. But following the example of the OrdinaryGetOwnProperty abstract operation I wrote about in the OP, OrdinaryOwnPropertyKeys would be specified as (diff from current shown):
I think this is a strict improvement in clarity from the current
Well, I have all the time in the world :) What do you think? |
sounds like a good plan.
In theory, you should not have to add anything to the definitions of the exotic objects in the ES spec. because they all are supposed to say something like: "String exotic objects have the same internal slots as ordinary objects. They also have a [[StringData]] internal slot.". But this seems to be missing from Array exotic objects and Module Namespace exotic objects. It would be better to fix those omissions than to explicitly add [[Properties]] to every exotic object specification. |
Ah, that's what I meant. Proposed spec text: Remove clause 6.1.7.1 Property AttributesAmend clause 6.2.5 The Property Descriptor Specification Type(add) The default values for each field of a Property Descriptor value are defined in Table 4: https://tc39.github.io/ecma262/#table-4 Add clause 6.2.6 The Property Map Specification TypeThe Property Map type is used to describe own properties of ordinary objects (see 9.1) and built-in exotic objects (see 9.4). Each value of the Property Map type consists of zero or more associations between a String- or Symbol-typed key and a fully populated Property Descriptor value. Each one of these associations is called a property. Each key in a Property Map value must be unique, in that the same key can map to at most one Property Descriptor in a given Property Map value. A data property associates a key with a data Property Descriptor, while an accessor property associates a key with an accessor Property Descriptor. While this specification does not prescribe the underlying data structure used to implement Property Map, the specification may carry out the following operations with or on Property Map values:
Amend 9.1 Ordinary Object Internal Methods and Internal Slots(existing) Every ordinary object has a Boolean-valued [[Extensible]] internal slot ... (add) Every ordinary object also has an internal slot named [[OwnProperties]] that is a value of the Property Map type. The [[OwnProperties]] internal slot contains all own properties this ordinary object possesses, but does not contain information about inherited properties the ordinary object may have. (existing) In the following algorithm descriptions, ... Amend 9.1.x.x Ordinary*See original post: #1067 (comment) See also: #1067 (comment) Amend 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
Amend 9.4 Built-in Exotic Object Internal Methods and Slots(existing with amendments) This specification defines several kinds of built-in exotic objects. These objects generally behave similar to ordinary objects except for a few specific situations. The following exotic objects use the ordinary object internal methods except where it is explicitly specified otherwise below: Example: 9.4.1 Bound Function Exotic Objects(existing with amendments) Bound function objects do not have the internal slots of ECMAScript function objects defined in Table 27. Instead they have the internal slots defined in Table 28. They do however have the same internal slots as ordinary objects (see 9.1). 9.4.2 Array Exotic Objects(existing with amendments) Array exotic objects provide an alternative definition for the [[DefineOwnProperty]] internal method. Except for that internal method, Array exotic objects provide all of the other essential internal methods as specified in 9.1. Array exotic objects also have the internal slots ordinary objects do (see 9.1). 9.4.x Etc.Amend 9.5 Proxy Object Internal Methods and Internal Slots(existing with amendments) ... This object is called the proxy's target object. Proxy exotic objects do not have any other internal slots, including the internal slots that all ordinary objects have (see 9.1). |
I would suggest using a List, and then in for-in, explicitly allowing the list to be shuffled into any order before enumerating it. Introducing a new Property Map specification type seems wasteful. |
When you say that the 6 Property Descriptor fields have default values, do you mean that every PD record has all 6 fields (where the not-explicitly-specified ones have their default values)? If so, then algorithm conditions that test for the presence/absence of a field in a PD will always be true/false by definition. Which is at least an opportunity for code clean-up, but possibly a normative change. |
Please no, this is much too big of a change and screws up the layering of the abstractions. I thought we were in agreement on a much smaller set of clarifications. 6.7.1 is an important part of the definition of ECMAScript language type Object. Nothing in it needs to be changed. It is all independent of defining ordinary or specific kinds of exotic objects. Just leave it alone. 6.2.4 works just fine as it is in connection with 6.7.1. Note that default values applies to properties actually defined within an object. Property are used to convey properties and property state changes separate from objects. Property descriptors do not need to fully populated with attributes, and a missing attribute in a descriptor does not mean use the default. It means don't muck with the current value. Adding a hole new specification type is completely unnecessary and an overkill for what you are trying to accomplish. Specifications types are generally defined for abstractions that need to be used throughout the specification. What we are talking about here should logically be an encapsulated part of the ordinary object specification. At most all you need to say is that a [[OwnProperties]] is an initially empty list of property definitions and where each property definition consists of a property key and a fully populated property descriptor. If you think it would simplify things for you, you could at that point define a "property definition" as a Records with two fields, [[key]] and [[descriptor]]. But the existing language used in 9.1 which talks about properties in terms of property keys and property attribute value would still be fine without explicitly defining a Record to represent it. I do see why you need to change the introductory paragraphs of 9.4. Bound functions: Array exotic objects: Overall, the goal here should be a very small set of editorial clarifications. You aren't actually changing anything. BTW, you should probably make sure that the current editor is in the loop for this sort of change. |
(Legacy bug 3812 referenced in the original post can be found here.) |
The Issue
From discussion on IRC, and Bug 3812 on the legacy Bugzilla:
The current definition of Object properties is unintuitive and even confusing to some. Per 6.1.7 The Object Type, "An Object is logically a collection of properties." Yet, these properties are not intended to be accessed directly, only through their internal methods. This contributes to seemingly circular definitions of internal methods such as OrdinaryGetOwnProperty:
while the unfortunately named HasOwnProperty abstract operation in turn calls OrdinaryGetOwnProperty by way of it being the [[GetOwnProperty]] internal method of many objects.
The status quo also mandates the seemingly unnecessary separation of Property Attributes (used only when accessing these properties internally) and Property Descriptors.
The Proposal
Define Objects instead as "a collection of internal methods and internal slots." As with the status quo, all Objects must have the essential internal methods, and also possibly [[Call]] and [[Construct]]. Different from the status quo, each Object also has a [[Properties]] (or [[IntrinsicProperties]]; name up for bikeshedding) internal slot, that is a "collection of properties" (a key-to-Property Descriptor mapping) this Object contains – to wit, separating out the current definition of an Object to an internal slot of one.
(A List is not used for the internal slot to preserve the legacy
for
-in
iteration order behavior.)With this definition, OrdinaryGetOwnProperty can instead be specified as:
ValidateAndApplyPropertyDescriptor:
(The language is a bit rough at the moment, but the idea should be clear.)
This is only an editorial change to the spec in the sense that it does not add or remove normative requirements.
CC @jmdyck @ljharb @domenic
The text was updated successfully, but these errors were encountered: