Skip to content
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

Why doesn't the specification describe the creation of built-in objects? #1491

Open
dSalieri opened this issue Mar 23, 2019 · 23 comments
Open

Comments

@dSalieri
Copy link

In chapter 17 ECMAScript Standard Built-in Objects very clearly describes the moments related to built-in objects (a lot has been written about function objects). Especially it concerns the built-in functions, there is a line that says:

Each built-in function defined in this specification is created by calling the CreateBuiltinFunction abstract operation (9.3.3).

But there is no such line about built-in objects that are not functions.
That is, there is a function to create ordinary functions (FunctionCreate) and built-in functions (CreateBuiltinFunction). There is also a function for creating ordinary objects (ObjectCreate), but there is no function for creating built-in objects.

What is the reason for the absence of the function for creating built-in objects?

@jmdyck
Copy link
Collaborator

jmdyck commented Mar 23, 2019

There isn't much in common between the built-in non-functions. If #1460 goes though, we could say that each one's creation involves a call to AllocatBaseObject/MakeDefaultObject, but I don't think it'd be a good idea.

@dSalieri
Copy link
Author

dSalieri commented Mar 26, 2019

@jmdyck I think it does not matter whether there is a difference between ordinary and built-in objects or not. The point is that the specification must clearly define the creation of something, in this case the creation of built-in objects. I did not find a step where it is clearly stated that the objects that are defined as "ordinary object" should be created through the "x" algorithm, and the objects that are defined as "exotic object" should be created through the "y" algorithm. In principle, the specification of exotic objects specifically described. But ordinary objects are not described how to create them. For example, the built-in Math object, it is not specified how it should be created, that is, there is no specific algorithm. And how should I know how to create it?

@jmdyck
Copy link
Collaborator

jmdyck commented Mar 26, 2019

The point is that the specification must clearly define the creation of something, in this case the creation of built-in objects.

No, it must clearly define the (observable) behavior of things. You can't observe the specifics of an object's creation, so the spec doesn't have to define it. (It can, but it doesn't have to.)

For example, the built-in Math object, it is not specified how it should be created, that is, there is no specific algorithm. And how should I know how to create it?

You can create it in any way that you like, as long as the result has the characteristics that the Math object is required to have.

@dSalieri
Copy link
Author

@jmdyck

You can't observe the specifics of an object's creation

Why? For example ObjectCreate

What is wrong then?

@jmdyck
Copy link
Collaborator

jmdyck commented Mar 26, 2019

ObjectCreate is an example of where the spec uses an abstract operation to define the specifics of an object's creation. But this is an editorial choice.

For instance, the step:
Let _x_ be ObjectCreate(%ObjectPrototype%).
could be replaced with:
Let _x_ be a new ordinary object whose [[Prototype]] is %ObjectPrototype%.
and it would have the same normative effect, based on the prose definition of "ordinary object".

@dSalieri
Copy link
Author

@jmdyck Interesting. It is clear that it does not specifically say how an object should be created, but instead it shows what an object should have. But since ObjectCreate exists, why not make ObjectBuiltinCreate for obviousness?

@claudepache
Copy link
Contributor

@dSalieri There is no essential difference between built-in and non-built-in ordinary objects: you could just use ObjectCreate for both. Ditto for the built-in Array exotic object (namely, %ArrayPrototype%): just use ArrayCreate(0, %ObjectPrototype%). — But that would add verbosity, not clarity, because all those individual objects are already sufficiently clearly defined by other means in the spec.

@allenwb
Copy link
Member

allenwb commented Mar 28, 2019

See CreateIntrinsics and CreateBuiltinFunction

@jmdyck
Copy link
Collaborator

jmdyck commented Mar 28, 2019

why not make ObjectBuiltinCreate for obviousness?

That was your original question, so we're in danger of going round in circles. Instead, I suggest that you give a definition (header + algorithm) for this operation, and say how it would be referenced. Then we can discuss whether that would be clearer than the status quo.

@dSalieri
Copy link
Author

@jmdyck It was not difficult, because in my opinion it was necessary to make a change in the function CreateIntrinsics and almost duplicate the function ObjectCreate.

Let's start by changing the function CreateIntrinsics:
It needs to change part of step 13, instead of the sentence:

All object property values are newly created object values.

I suggest:

All values that are built-in objects are created by performing CreateBuiltinObject(< proto >,< slots >) where < proto > is the specified value of the object's [[Prototype]] internal slot and < slots > is a list of the names, if any, of the object's specified internal slots.

Well, the function that must match the name CreateBuiltinObject:

CreateBuiltinObject( proto [ , internalSlotsList] )

The abstract operation CreateBuiltinObject with argument proto is used to specify creation of built-in objects. The optional argument internalSlotsList is a List of the names of additional internal slots that must be defined as part of the object. If the list is not provided, a new empty List is used. This abstract operation performs the following steps:

  1. If internalSlotsList is not present, set internalSlotsList to a new empty List.
  2. Let obj be a newly created object with an internal slot for each name in internalSlotsList.
  3. If obj is exotic then:
    a. Set obj's internal methods to the exotic object definitions specified in 9.4.
    b. Set obj's missing essential internal methods to the default ordinary object definitions specified in 9.1.
  4. Else set obj's essential internal methods to the default ordinary object definitions specified in 9.1.
  5. Set obj.[[Prototype]] to proto.
  6. Set obj.[[Extensible]] to true.
  7. Return obj.

As the easiest option, you can simply write in function CreateIntrinsics in step 13:

All values that are built-in objects are created by performing ObjectCreate

but in this case there is not a word about exotic objects.

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 1, 2019

Step 3: It doesn't make sense to ask if obj is exotic, because you haven't yet set its essential internal methods, which are what you'd examine to determine if it is exotic. Instead, the test you want is more like If the desired object is specified to be exotic, but you can't ascertain that from the parameters.

Step 3a: Clause 9.4 specifies more than one set of exotic method definitions. And even if you devise a means to indicate just one of them, it becomes unclear whether (e.g.) %ArrayPrototype% should be created according to this operation or ArrayCreate. Moreover, this operation may be called upon to create an exotic object whose semantics isn't specified in Clause 9.4.

Step 4: As above, it becomes unclear whether ordinary non-function built-ins should be created according to this operation or ObjectCreate. It would be simpler to just invoke ObjectCreate.

Steps 5+6: It isn't guaranteed that a built-in object will have [[Prototype]] and [[Extensible]] slots. (An object without them would have to be an exotic not defined in the spec, I think.)

All values that are built-in objects are created by performing ObjectCreate
but in this case there is not a word about exotic objects.

Right, which is why that option is a non-starter.

@dSalieri
Copy link
Author

dSalieri commented Apr 3, 2019

@jmdyck

My third step is based on the fact that we understand which object we are creating and if this object belongs to a group of exotic objects, then we apply the rules that I described above.


You can create a table that will specifically indicate the desired exotic object. In addition, when creating an exotic object through CreateBuiltinObject, you can specifically show whether ArrayCreate will be used or not.


Yes, probably you are right it would be easier to create with the ObjectCreate operation, but the goal is to show how internal objects are created.


It is then necessary to somehow identify these slots ([[Prototype]] and [[Extensible]]), because they may be in ordinary objects, but not in exotic ones.

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 3, 2019

My third step is based on the fact that we understand which object we are creating

I understand what the step is trying to do. What you've written doesn't do that.

Yes, probably you are right it would be easier to create with the ObjectCreate operation, but the goal is to show how internal objects are created.

Using ObjectCreate doesn't conflict with that goal. Rather, it seems quite useful in meeting that goal.

You can create a table that will specifically indicate the desired exotic object.

You could, but (a) you'd have to tell the operation which row is pertinent to any given invocation, and (b) that still wouldn't take care of exotic objects whose semantics aren't defined in 9.4.

In addition, when creating an exotic object through CreateBuiltinObject, you can specifically show whether ArrayCreate will be used or not.

You mean pass ArrayCreate (or some other object-creating operation) to CreateBuiltinObject? Okay, then you can scrap the whole table idea. But then you'd basically just have:

All values that are built-in objects are created by performing
CreateBuiltinObject(<object-creating-operation>, <creation-args>),
where <object-creating-operation> is an abstract operation
that creates an object (e.g. ArrayCreate or ObjectCreate),
and <creation-args> is a list of arguments (if any) for that operation.

CreateBuiltingObject(_op_, _args_)
1. Return the result of applying _op_ to _args_.

Which seems like an unnecessarily complex way to just say:

All values that are built-in objects are created by 
invoking an abstract operation that creates an object
(e.g. ArrayCreate or ObjectCreate)
with a list of arguments.

@dSalieri
Copy link
Author

dSalieri commented Apr 5, 2019

@jmdyck Then how to properly express this step?


It does not contradict, but does not reach to cover all objects.


No, I didn't mean, but I like your concept (it is almost the same but only the creation method is specified in the algorithm, and not through the argument).


In general, I would change your text a bit to the following:

All built-in objects that are ordinary objects are created using the ObjectCreate operation, and exotic objects are created using the operations listed in chapter 9.4. If the description of the object does not indicate its ownership, then its creation depends on the implementation

By the way, what did you mean by:

(b) that still wouldn't take care of exotic objects whose semantics aren't defined in 9.4.

How can I get an exotic object (I read the definition of an exotic object and understand perfectly what it means)?

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 5, 2019

(@dSalieri: You should give a bit more context so I know what each thing is responding to.)

@jmdyck Then how to properly express this step?

(This is presumably about step 3 "If obj is exotic ...".)

Currently, I don't think the spec has a convention for expressing it. As I said: "Instead, the test you want is more like If the desired object is specified to be exotic, but you can't ascertain that from the parameters."

It does not contradict, but does not reach to cover all objects.

(I think this is about the use of ObjectCreate.)

Sure, ObjectCreate doesn't "cover" all objects. But it can cover all ordinary objects, which is all that Step 4 is concerned with.

In general, I would change your text a bit to the following:

All built-in objects that are ordinary objects are created using the ObjectCreate operation, and exotic objects are created using the operations listed in chapter 9.4. If the description of the object does not indicate its ownership, then its creation depends on the implementation

We could conceivably put a sentence like the first in CreateIntrinsics. But (a) we'd have to restrict it to non-function objects, and (b) we can't limit exotics to 9.4.

As for the second sentence, it's unclear what you mean by ownership.

By the way, what did you mean by:

(b) that still wouldn't take care of exotic objects whose semantics aren't defined in 9.4.

Well, for one thing, proxy objects are exotic, and they're defined in 9.5. For another thing, implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec.

How can I get an exotic object (I read the definition of an exotic object and understand perfectly what it means)?

I'm not sure I understand the question. There isn't a single way to "get" an exotic object. You could access a pre-existing exotic object (e.g. Array.prototype) or make one yourself (e.g. Array() or Function.prototype.bind(...) or Proxy(...)).

@dSalieri
Copy link
Author

dSalieri commented Apr 7, 2019

(@jmdyck this time I will make the context, since it is difficult to understand what specifically refers to, but you understood everything correctly last time :))

Currently, I don't think the spec has a convention for expressing it. As I said: "Instead, the test you want is more like If the desired object is specified to be exotic, but you can't ascertain that from the parameters."

That is, it cannot be determined whether the object is exotic or not?

We could conceivably put a sentence like the first in CreateIntrinsics. But (a) we'd have to restrict it to non-function objects, and (b) we can't limit exotics to 9.4.

I do not quite understand what you mean by: like the first in CreateIntrinsics? And what is the difficulty of restricting non-functional objects? As for the exotic: well, if it is impossible to restrict the exotic, then it may be worth simply listing the paragraphs in which there is exotic or introducing a general sentence that will talk about how exotic can still be created?

As for the second sentence, it's unclear what you mean by ownership.

I meant belonging to a specific category of objects, in this case, the absence of belonging to any of the categories.

Well, for one thing, proxy objects are exotic, and they're defined in 9.5. For another thing, implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec.

About the proxy object. If I am not mistaken, he does not belong to the group of built-in objects.
Built-in is its constructor.
And we are talking about built-in objects. Then I do not quite understand how proxy objects relate to the creation of built-in objects? It seems that there is no built-in proxy object? Or is there?
As for:implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec., I think it is worth making a proposal that explains this too?

How can I get an exotic object (I read the definition of an exotic object and understand perfectly what it means)?

I'm not sure I understand the question. There isn't a single way to "get" an exotic object. You could access a pre-existing exotic object (e.g. Array.prototype) or make one yourself (e.g. Array() or Function.prototype.bind(...) or Proxy(...)).

I did not notice this, you already answered my question above, when you said that there are proxy objects with definition 9.5.


Well, then it is necessary to amend my modified text and it will look like this:

All built-in objects that are ordinary objects are created using the ObjectCreate operation, and built-in objects that are exotic objects are created using the operations listed in chapter 9.4. If the description of an object does not specify its type (for example, as in a Math object that has is an ordinary object string), its creation depends on the implementation (in the end, its type will be determined by the presence of internal slots and their functionality). Built-in objects that are not described by the specification and are created by the will of the implementation have an object type that is clearly described in this specification (All object types are listed in chapter 4.3)

Why not paste this text into item 13 of the CreateIntrinsics function?

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 7, 2019

As I said: "Instead, the test you want is more like If the desired object is specified to be exotic, but you can't ascertain that from the parameters."

That is, it cannot be determined whether the object is exotic or not?

No, that can be determined, but that's not what your test (in step 3) is trying to do. It's trying to determine whether obj is meant to become an exotic object, not whether it is an exotic object.

We could conceivably put a sentence like the first in CreateIntrinsics. But (a) we'd have to restrict it to non-function objects, and (b) we can't limit exotics to 9.4.

I do not quite understand what you mean by: like the first in CreateIntrinsics?

I meant that we could put, into CreateIntrinsics, a sentence like the first one you gave. ("All built-in objects that are ordinary objects are created using the ObjectCreate operation, and exotic objects are created using the operations listed in chapter 9.4.")

And what is the difficulty of restricting non-functional objects?

No difficulty, it would just need to be done.

As for the exotic: well, if it is impossible to restrict the exotic, then it may be worth simply listing the paragraphs in which there is exotic or introducing a general sentence that will talk about how exotic can still be created?

Listing paragraphs doesn't sound useful. A general sentence might be, but I'm doubtful.

As for the second sentence, it's unclear what you mean by ownership.

I meant belonging to a specific category of objects, in this case, the absence of belonging to any of the categories.

The spec doesn't talk about "categories" of objects either.

Well, for one thing, proxy objects are exotic, and they're defined in 9.5. For another thing, implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec.

About the proxy object. If I am not mistaken, he does not belong to the group of built-in objects. [...]
Then I do not quite understand how proxy objects relate to the creation of built-in objects?

An implementation can provide a built-in object that's a proxy object.

It seems that there is no built-in proxy object? Or is there?

I don't think there are any built-in proxy object defined by the ES spec, but ES implementations can provide built-in objects that are not defined by the ES spec, inluding built-in proxy objects.

As for:implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec., I think it is worth making a proposal that explains this too?

Clause 2 Conformance says "A conforming implementation of ECMAScript may provide additional types, values, objects, properties, and functions beyond those described in this specification."

And a Note in 4.3.9 built-in object says "Standard built-in objects are defined in this specification. An ECMAScript implementation may specify and supply additional kinds of built-in objects."


Well, then it is necessary to amend my modified text and it will look like this:

All built-in objects that are ordinary objects are created using the ObjectCreate operation, and built-in objects that are exotic objects are created using the operations listed in chapter 9.4.

As I said, you have to restrict this to non-functions, and you can't limit exotics to 9.4.

If the description of an object does not specify its type

As soon as you say it's an object, you've specified its type. 'Object' is a type.

(for example, as in a [Math] object that has is an ordinary object string), its creation depends on the implementation

All built-ins are created by the implementation, so it's unclear what you mean by saying the for some of them, the creation "depends on" the implementation.

(in the end, its type will be determined by the presence of internal slots and their functionality).

Nope. Whatever you're thinking of is not what the ES spec calls its type.

Built-in objects that are not described by the specification and are created by the will of the implementation have an object type that is clearly described in this specification

That's basically just saying that a particular subset of objects are objects, which doesn't seem very useful.

(All object types are listed in chapter 4.3)

Nope. There's only one Object type, and most of the terms defined by 4.3 don't even refer to objects.

@dSalieri
Copy link
Author

dSalieri commented Apr 8, 2019

@jmdyck

No, that can be determined, but that's not what your test (in step 3) is trying to do. It's trying to determine whether obj is meant to become an exotic object, not whether it is an exotic object.

I then do not understand how to do it. Need help probably :)

If you can insert this sentence:

"All built-in objects that are ordinary objects are created using the ObjectCreate operation, and exotic objects are created using the operations listed in chapter 9.4."

then how to restrict non-functional objects? And what to do with exotic once it can not be restricted?

The spec doesn't talk about "categories" of objects either.

Yes, I distorted a little when I said about the categories, but I think that you understood what I meant by that, right?

An implementation can provide a built-in object that's a proxy object.

It seems that there is no built-in proxy object? Or is there?

I don't think there are any built-in proxy object defined by the ES spec, but ES implementations can provide built-in objects that are not defined by the ES spec, inluding built-in proxy objects.

As for:implementations can provide built-in exotic non-function objects whose semantics aren't defined anywhere in the spec., I think it is worth making a proposal that explains this too?

Clause 2 Conformance says "A conforming implementation of ECMAScript may provide additional types, values, objects, properties, and functions beyond those described in this specification."

And a Note in 4.3.9 built-in object says "Standard built-in objects are defined in this specification. An ECMAScript implementation may specify and supply additional kinds of built-in objects."

Yeah, well, then the implementation itself can determine its proxy object, regardless of the standard, accepted. About links is also understandable.


As I said, you have to restrict this to non-functions, and you can't limit exotics to 9.4.

Yes, I understood it. But I honestly do not understand what exactly I should do for this.

(for example, as in a [Math] object that has is an ordinary object string), its creation depends on the implementation

All built-ins are created by the implementation, so it's unclear what you mean by saying the for some of them, the creation "depends on" the implementation.

Well, but what then is the string is an ordinary object? Description of the object? Is an ordinary object not a subtype of an object?

Built-in objects that are not described by the specification and are created by the will of the implementation have an object type that is clearly described in this specification

This line was written for cases that are not described by the specification. But you have already answered above 2 links where about it said.

(All object types are listed in chapter 4.3)

It is clear, but all the "types" of objects are also listed there. I just do not always know how to properly say.

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 9, 2019

how to restrict non-functional objects?

You can use wording like "For built-in objects that are not functions, ..."

The spec doesn't talk about "categories" of objects either.

Yes, I distorted a little when I said about the categories, but I think that you understood what I meant by that, right?

Possibly, but when you're proposing new spec text, it's dangerous to use terms that the spec doesn't define: you can't assume that the reader will understand what you intended.

Well, but what then is the string is an ordinary object? Description of the object? Is an ordinary object not a subtype of an object?

Not as far as the spec is concerned, because it doesn't define that term. (It does use it once, but that's probably a bug.)

(All object types are listed in chapter 4.3)

It is clear, but all the "types" of objects are also listed there.

It depends on what you mean when you say "types of objects". For instance, you might think of Array as a "type of object", but "Array object" is not defined in 4.3.

@dSalieri
Copy link
Author

dSalieri commented Apr 15, 2019

@jmdyck You can then use a wording of this type:

Built-in objects that are ordinary objects and are not functions are created using the ObjectCreate operation. Built-in objects that are exotic objects, but which are not functions, and which are specifically described by the specification are created using the operations listed in chapter 9.4. Creating built-in exotic objects that are not described in this specification is implementation-dependent.

Not as far as the spec is concerned, because it doesn't define that term. (It does use it once, but that's probably a bug.)

Why is this a bug? In the specification there is a definition ordinary object. And there are matches in this specification for string:is an ordinary object.

It depends on what you mean when you say "types of objects". For instance, you might think of Array as a "type of object", but "Array object" is not defined in 4.3.

By the way, why is there no Array Object in 4.3 chapter, but is there a Boolean Object? As I noticed there is not all there.

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 15, 2019

@jmdyck You can then use a wording of this type:

Built-in objects that are ordinary objects and are not functions are created using the ObjectCreate operation. Built-in objects that are exotic objects, but which are not functions, and which are specifically described by the specification are created using the operations listed in chapter 9.4. Creating built-in exotic objects that are not described in this specification is implementation-dependent.

Yeah, that seems like a plausible addition.

Not as far as the spec is concerned, because it doesn't define that term. (It does use it once, but that's probably a bug.)

Why is this a bug? In the specification there is a definition ordinary object. And there are matches in this specification for string:is an ordinary object.

I was referring to the term "subtype": the spec doesn't define it, uses it only once, and that use is probably a bug.

It depends on what you mean when you say "types of objects". For instance, you might think of Array as a "type of object", but "Array object" is not defined in 4.3.

By the way, why is there no Array Object in 4.3 chapter, but is there a Boolean Object? As I noticed there is not all there.

Clause 4.3 doesn't claim to define all terms, or to be complete in any sense. I imagine "Boolean object" is there to distinguish it from "Boolean value". "Array object" doesn't have that problem.

@dSalieri
Copy link
Author

dSalieri commented Apr 20, 2019

@jmdyck

Clause 4.3 doesn't claim to define all terms, or to be complete in any sense. I imagine "Boolean object" is there to distinguish it from "Boolean value". "Array object" doesn't have that problem.

Interesting

I was referring to the term "subtype": the spec doesn't define it, uses it only once, and that use is probably a bug.

Sometimes, I can not understand what it is about, but now it is clear :)


But what about:

Yeah, that seems like a plausible addition.

@jmdyck
Copy link
Collaborator

jmdyck commented Apr 20, 2019

But what about:

Yeah, that seems like a plausible addition.

If you think the addition would be an improvement, you can submit a pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants