[[Class]] and host objects

# Allen Wirfs-Brock (17 years ago)

At the Mountain view meeting we agreed to "remove the host object exemption" regarding [[Class]] so we could reliably use it discriminate "types" of objects. I'm trying to implement this in the specification, but what does it really mean?

ES3 currently says: "The value of the [[Class]] property of a host object may be any value, even a value used by a built-in object for its [[Class]] property." (8.6.2). This is the exemption we agreed to remove.

If we simply remove this sentence there is still an explicitly statement requirement that all host objects must have a [[Class]] property but there is then no guidance at all about what is allowable as its value. That might be interpreted to mean pretty much the same thing as the deleted sentence.

I assume that we wanted to allow under some circumstances for host objects to have a [[Class]] value that is the same as one of the built-in values ("Object" comes to mind ). If so, what are those circumstances. Short of explicitly enumerating all the invariants that must be satisfied for each built-in [[Class]] value is there any way to express when a host object is allowed to use of these values?

My first cut was to replace the ES3 sentence with: "The value of the [[Class]] property of a host object may be any String value. However, if a host objects has a [[Class]] property whose value is the same as that defined by this specification for a built-in object then the host object must conform to all requirements associated with that built-in object."

But what does that really mean. Which "requirements" are we talking about? That the host object must fully implement the Section 15 specification of the corresponding built-in object? In that case, isn't such a host object really just a way to implement the native object. In other words, it's actually a native object not a host object at all? In that case we probably also don't need to say anything.

Is it really the intent that any object whose [[Class]] is "Array" must fully implement 15.4.5? One of the things that 15.4.5 says is that array instances inherit from the original Array prototype object. Is this a requirement of [[Class]]=="Array"? If so, what about array objects that come from different contexts that have a different Array prototype object? Is the requirement really only that "Array" objects implement the special [[ThrowingPut]] method defined in 15.4.5.1.

I've tried various formulation of a simple statement about host objects but I keep finding potential holes and coming back to the conclusion that the only meaningful thing to do is to explicitly enumerable the invariants associated with each predefined [[Class]] value. Does anybody have a simpler solution? Does anybody want to volunteer to identify the invariants?

# Brendan Eich (17 years ago)

On Feb 6, 2009, at 5:01 PM, Allen Wirfs-Brock wrote:

I assume that we wanted to allow under some circumstances for host
objects to have a [[Class]] value that is the same as one of the
built-in values (“Object” comes to mind ).

Note that the arguments objects must seem to have [[Class]] ==
"Object" (the Object.prototype.toString.call(arguments) test).

But what does that really mean. Which “requirements” are we talking
about? That the host object must fully implement the Section 15
specification of the corresponding built-in object? In that case,
isn’t such a host object really just a way to implement the native
object. In other words, it’s actually a native object not a host
object at all? In that case we probably also don’t need to say
anything.

Think tiered virtual machines where for N > 1, tier N's Object is tier

N-1's host emulation with [[Class]] == "Object" but extra hooks and
metamagic, backstage of tier N's reality.

How can tier N tell? It can't. But the only truly "native"
implementation of Object would be tier 1's.

I shall avoid getting into Descarte, Baudrillard, or "The Matrix",
here :-P.

Is it really the intent that any object whose [[Class]] is “Array”
must fully implement 15.4.5? One of the things that 15.4.5 says is
that array instances inherit from the original Array prototype
object. Is this a requirement of [[Class]]==”Array”? If so, what
about array objects that come from different contexts that have a
different Array prototype object?

The spec going back to ES1 has pretty much failed to deal with
multiple global objects. We talked about this at the meeting, and IIRC
you were inclined to try an informative TR or Annex. :-)

Is the requirement really only that “Array” objects implement the
special [[ThrowingPut]] method defined in 15.4.5.1.

No, there has to be more to it than that.

I’ve tried various formulation of a simple statement about host
objects but I keep finding potential holes and coming back to the
conclusion that the only meaningful thing to do is to explicitly
enumerable the invariants associated with each predefined [[Class]]
value. Does anybody have a simpler solution? Does anybody want to
volunteer to identify the invariants?

I think Chapter 15 already does identify the invariants, but you're
right that multiple globals are not specified. In a single-global
embedding, I would want any host [[Class]] == "Array" impostor to
create instances whose prototype was Array.prototype, though. Wouldn't
you?

# Waldemar Horwat (17 years ago)

Brendan Eich wrote:

I’ve tried various formulation of a simple statement about host objects but I keep finding potential holes and coming back to the conclusion that the only meaningful thing to do is to explicitly enumerable the invariants associated with each predefined [[Class]] value. Does anybody have a simpler solution? Does anybody want to volunteer to identify the invariants?

I think Chapter 15 already does identify the invariants, but you're right that multiple globals are not specified. In a single-global embedding, I would want any host [[Class]] == "Array" impostor to create instances whose prototype was Array.prototype, though. Wouldn't you?

Not necessarily. Array.prototype could be further up the prototype chain, or perhaps they could share a common prototype that constitutes a more generic kind of arrayness than Array.

As you guys mentioned, the bigger question is what to do about multiple global objects. That's the issue in reality and we shouldn't add anything to the spec that would be inconsistent with that reality.

Waldemar
# Allen Wirfs-Brock (17 years ago)

-----Original Message----- From: Waldemar Horwat [mailto:waldemar at google.com] Sent: Monday, February 09, 2009 6:30 PM ...

As you guys mentioned, the bigger question is what to do about multiple global objects. That's the issue in reality and we shouldn't add anything to the spec that would be inconsistent with that reality.

Waldemar

I'm inclination is say that we should explicitly specify for each [[Class]] value used in the specification only and exactly the invariants that something in the specification actually depends upon. Anything else seems to be outside the scope of the specification and there is no good way so select which of the Section 15 characteristics do or don't need to be specified.

Other than toString I believe that the only directly user observable use of [[Class]] is the new Array.isArray function. The main use case for this was Doug's JSON libraries that needed to determine which objects should be output using array literal notation. We now have enough reflection support that he could write any sort of Array litmus test that he thought was appropriate (for example, length property value == largest numeric property name + 1). Given that, maybe we don't really need Array.isArrary which would probably simply the what does [[Class]]=="Array" mean discussion.

# Douglas Crockford (17 years ago)

Other than toString I believe that the only directly user observable use of [[Class]] is the new Array.isArray function. The main use case for this was Doug's JSON libraries that needed to determine which objects should be output using array literal notation. We now have enough reflection support that he could write any sort of Array litmus test that he thought was appropriate (for example, length property value == largest numeric property name + 1). Given that, maybe we don't really need Array.isArrary which would probably simply the what does [[Class]]=="Array" mean discussion.

There are lots of other uses for an isArray test. Since we can't fix typeof, Array.isArray is necessary.

The question is how does isArray work, does it look for [[Class]]=="Array" or does it do something more mysterious. If we can settle on what [[Class]] does, then that would seem better.

# Brendan Eich (17 years ago)

On Feb 9, 2009, at 6:29 PM, Waldemar Horwat wrote:

Brendan Eich wrote:

I’ve tried various formulation of a simple statement about host
objects but I keep finding potential holes and coming back to the
conclusion that the only meaningful thing to do is to explicitly
enumerable the invariants associated with each predefined
[[Class]] value. Does anybody have a simpler solution? Does
anybody want to volunteer to identify the invariants? I think Chapter 15 already does identify the invariants, but you're
right that multiple globals are not specified. In a single-global
embedding, I would want any host [[Class]] == "Array" impostor to
create instances whose prototype was Array.prototype, though.
Wouldn't you?

Not necessarily. Array.prototype could be further up the prototype
chain, or perhaps they could share a common prototype that
constitutes a more generic kind of arrayness than Array.

I'm against such ontological confusion :-P.

It's true that almost all Array methods are generic (toString isn't,
as seen below), but the custom [[Put]] in ES1-3, now [[ThrowingPut]]
in 3.1, would be on a prototype and so would not be called when
indexed properties were assigned to the directly referenced array-like
object:

js> a = []

js> o = {proto:a} // Object.create in ES3.1

Array.prototype.toString called on incompatible Object js> o.toString = function()this.join(",")

function () this.join(",") js> o

js> o[0]=0

0 js> o[1]=1

1 js> o

js> o.length

0 js> o[0]

0 js> o.hasOwnProperty(0)

true

A host object that has Array.prototype on its prototype chain could do
more work by defining a [[ThrowingPut]] that maintains length, but the
spec would have to say that such a [[ThrowingPut]] works exactly the
same as the one spec'ed in 15.4.5.1.

Object.getPrototypeOf would disclose a difference in prototype
relations from "real" Arrays too.

There are several notions of "array-like" or "arrayness", where an
object:

  • has a .length property whose uint32 value is one greater than the
    maximum uint32 conversion of any property name that converts back to
    the same string name.

  • has a .length property that can be set to a lesser value than its
    current value to truncate or extend the set of indexed properties (not
    all would-be arraylikes can be truncated or extended in my experience).

  • has the Array.prototype generic method suite, and possibly a
    toString that works the same as Array.prototype.toString.

  • has Array.prototype on its prototype chain, either immediately or
    further up the [[Prototype]]-linked chain.

The meaning of [[Class]] == "Array" should include all of these, and I
think Array.prototype should be the immediate prototype.

In implementations, [[Class]] corresponds to a native class (vtable)
that implements [[ThrowingPut]], [[Prototype]], and other spec- internal properties. An implementation might be able to mix in
different native classes but they would not be composed along the
prototype chain. I'm not sure how the spec would even talk about such
implementations, other than by doing what Allen said and requiring
indistinguishability from native Array objects. Having Array.prototype
as other than the immediate prototype breaks indistinguishability.

# Brendan Eich (17 years ago)

On Feb 10, 2009, at 1:52 PM, Brendan Eich wrote:

  • has a .length property that can be set to a lesser value than its
    current value to truncate or extend the set of indexed properties
    (not all would-be arraylikes can be truncated or extended in my
    experience).

s/lesser/different/

# Allen Wirfs-Brock (17 years ago)

-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss- bounces at mozilla.org] On Behalf Of Douglas Crockford Sent: Tuesday, February 10, 2009 12:26 PM ... There are lots of other uses for an isArray test. Since we can't fix typeof, Array.isArray is necessary.

The question is how does isArray work, does it look for [[Class]]=="Array" or does it do something more mysterious. If we can settle on what [[Class]] does, then that would seem better.

No, the question is "what does it mean?" If we can decide that, we can decide how to specify it. What specific guarantees are you expecting when Array.isArray returns true? Everything specified in 15.4 excludeing 15.4.1-15.4.3 (constructor stuff)?

If you want to use [[Class]]=="Array" to specify isArray and also expect to restrict host object use of [[Class]=="Array" to host objects that conform to some invariant we must specify what that invariant is.

I guess it is time for one of my alternative lists. The original question was what if any restrictions should ES3.1 place upon host objects' [[Class]] values. The alternatives on the table are:

  1. An implementation can give any host object any [[Class]] value it wants, including value that have specified meanings within the spec. This is what ES3 says.
  2. An implementation may not use any of the specified [[Class]] values for a host object. 2a) An implementation may only use the specified [[Class]] values for a host object that is a fully conforming implement of a Section 15 object. (in which case, it is probably really a native object and not a host object at all).
  3. An implementation may only use the specified [[Class]] values for host objects that conform to some specified set of invariants that ES3.1 specifies for each such [[Class]] value.

.#1 is what we have now with ES3 and at least some of us want to tighten the specification because it currently means when in the presence of host objects that testing [[Class]] guarantees nothing.

.#2 seem nice and simple to me but may not be a good fit with existing implementations and probably requires rethinking of [[Class]]=="Function" predicates in the Function.prototype.bind algorithm. #2a ultimately seem the same as #2

.#3 would be fine but requires work. We would need to decide on the invariants for specified [[Class]] value.

(parting shot, if [[Class]] was really called [[ToStringIdentifier]] would we even be having this conversation?)

# Mark Miller (17 years ago)

On Tue, Feb 10, 2009 at 1:52 PM, Brendan Eich <brendan at mozilla.com> wrote:

I'm against such ontological confusion :-P.

Me too!

[...] I'm not sure how the spec would even talk about such implementations, other than by doing what Allen said and requiring indistinguishability from native Array objects. [...]

Agreed on all points. But we can state this more simply. If an object is not observably distinguishable from a native Array object, then it simply is a native Array object. It is not a host object. A spec can only traffic in observably distinguishable differences. We can get the effect of specifying such indistinguishability simply by specifying that host objects may have as their [[Class]] property "Object", or any string not otherwise used by the spec as a [[Class]] value.

# Mark Miller (17 years ago)

On Tue, Feb 10, 2009 at 2:49 PM, Allen Wirfs-Brock < Allen.Wirfs-Brock at microsoft.com> wrote:

I guess it is time for one of my alternative lists.

Good. Thanks!

The original question was what if any restrictions should ES3.1 place upon host objects' [[Class]] values. The alternatives on the table are:

  1. An implementation can give any host object any [[Class]] value it wants, including value that have specified meanings within the spec. This is what ES3 says.
  2. An implementation may not use any of the specified [[Class]] values for a host object. 2a) An implementation may only use the specified [[Class]] values for a host object that is a fully conforming implement of a Section 15 object. (in which case, it is probably really a native object and not a host object at all).
  3. An implementation may only use the specified [[Class]] values for host objects that conform to some specified set of invariants that ES3.1 specifies for each such [[Class]] value.

#1 is what we have now with ES3 and at least some of us want to tighten the specification because it currently means when in the presence of host objects that testing [[Class]] guarantees nothing.

#2 seem nice and simple to me but may not be a good fit with existing implementations and probably requires rethinking of [[Class]]=="Function" predicates in the Function.prototype.bind algorithm. #2a ultimately seem the same as #2

#3 would be fine but requires work. We would need to decide on the invariants for specified [[Class]] value.

Yes, I am in favor of #2.

(parting shot, if [[Class]] was really called [[ToStringIdentifier]] would we even be having this conversation?)

Yes, but we may have then made the (IMO) mistake of introducing a new internal unforgeable nominal type property, such as your earlier [[IsArray]], but applicable as well to at least Date, RegExp, and Function, without noticing the unfortunate redundancy with the existing unforgeable [[ToStringIdentifier]] property.

# Allen Wirfs-Brock (17 years ago)

Mark Miller said: We can get the effect of specifying such indistinguishability simply by specifying that host objects may have as their [[Class]] property "Object", or any string not otherwise used by the spec as a [[Class]] value.

I generally agree, but I have two "what about's" that actually go in different directions from each other.

.#1 What about "Function" in addition to "Object"? It seems reasonable to have host objects that are functions in addition host objects that are objects. (Counter-argument: slippery slope)

.#2 Why allow "Object" for host objects that are required to conform to the section 15.3 specification for Object. If they are distinguishable from section 15.3 objects they should have [[Class]]=="Object". An implementation can use "HostObject" or something else. (Counter-argument: Might confuse some programmers??? (seems weak))

# Mark S. Miller (17 years ago)

2009/2/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>

Mark Miller said: We can get the effect of specifying such indistinguishability simply by specifying that host objects may have as their [[Class]] property "Object", or any string not otherwise used by the spec as a [[Class]] value.

I generally agree, but I have two "what about's" that actually go in different directions from each other.

#1 What about "Function" in addition to "Object"? It seems reasonable to have host objects that are functions in addition host objects that are objects. (Counter-argument: slippery slope)

#2 Why allow "Object" for host objects that are required to conform to the section 15.3 specification for Object. If they are distinguishable from section 15.3 objects they should have [[Class]]=="Object". An implementation can use "HostObject" or something else. (Counter-argument: Might confuse some programmers??? (seems weak))

I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

# Allen Wirfs-Brock (17 years ago)

Mark Miller: I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

That's what I thought until I probed around a few DOM objects in IE and Firefox and didn't see any [object "Object"]'s. We probably need the browser experts to tells whether or not it is common practice to use [[Class]]=="Object" for host objects but a casual inspection looked promising.

From: Mark S. Miller [mailto:erights at google.com] Sent: Tuesday, February 10, 2009 6:01 PM To: Allen Wirfs-Brock Cc: Mark Miller; Brendan Eich; es-discuss Subject: Re: [[Class]] and host objects

2009/2/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com<mailto:Allen.Wirfs-Brock at microsoft.com>>

Mark Miller said: We can get the effect of specifying such indistinguishability simply by specifying that host objects may have as their [[Class]] property "Object", or any string not otherwise used by the spec as a [[Class]] value.

I generally agree, but I have two "what about's" that actually go in different directions from each other.

.#1 What about "Function" in addition to "Object"? It seems reasonable to have host objects that are functions in addition host objects that are objects. (Counter-argument: slippery slope)

.#2 Why allow "Object" for host objects that are required to conform to the section 15.3 specification for Object. If they are distinguishable from section 15.3 objects they should have [[Class]]=="Object". An implementation can use "HostObject" or something else. (Counter-argument: Might confuse some programmers??? (seems weak))

I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

# Robert Sayre (17 years ago)

I am skeptical that we'll arrive at a definition of isArray that sounds proper and uses only observable properties of the language. I would prefer that we leave arrayness unspecified or settle on one major implementor's interpretation.

  • Rob

On Feb 10, 2009 9:01 PM, "Mark S. Miller" <erights at google.com> wrote:

2009/2/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>

Mark Miller said: We can get the effect of specifying such

indistinguishability simply by speci... I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

# Brendan Eich (17 years ago)

I don't see why a host object would claim [[Class]] == "Object" -- we
have custom classes throughout our DOM, so do others, but if you want
an object whose [[Class]] == "Object", you want an instance of the one
true native Object constructor.

The issue with host objects wanting to claim [[Class]] == "Function"
was not from IE or any browser I know of (recall that IE's alert is
not a function, rather a callable object). The issue may have been a
misinterpretation of host objects to mean all those not specified in
ECMA-262, which would seem to require DOM object methods to be host
objects whose [[Class]] == "Function". But that's not the case. Either
such methods are callables that do not claim to be functions (typeof
alert == "object"), or they are in fact native Function instances.

# Juriy Zaytsev (17 years ago)

On Feb 10, 2009, at 9:15 PM, Allen Wirfs-Brock wrote:

Mark Miller: I like your #2 direction a lot. If it were feasible to
require that host objects not even use [[Class]] "Object", I'd be in
favor. However, I'm guessing that would differ too greatly from
current browser behavior to have a chance.

That’s what I thought until I probed around a few DOM objects in IE
and Firefox and didn’t see any [object “Object”]’s. We probably
need the browser experts to tells whether or not it is common
practice to use [[Class]]==”Object” for host objects but a casual
inspection looked promising.

I actually see IE6 and 7 having "Object" for most of the host
methods' [[Class]]'es. I couldn't find any "Object" [[Class]] nether
in FF nor in Gecko. Both, Opera (9.61) and Chrome (1.x) return
"Object" for Element.prototype

[...]

# David-Sarah Hopwood (17 years ago)

Mark S. Miller wrote:

2009/2/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>

#2 Why allow "Object" for host objects that are required to conform to the section 15.3 specification for Object. If they are distinguishable from section 15.3 objects they should have [[Class]]=="Object". An implementation can use "HostObject" or something else. (Counter-argument: Might confuse some programmers??? (seems weak))

I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

Remember that, apart from algorithms that check whether [[Class]] is "Function", "Date" or "RegExp", the only other observable effect of [[Class]] is on the default implementation of toString(). A host object can override toString() anyway.

A reliable way of distinguishing native from host objects, say an Object.isNativeObject(o) method, might actually be useful for secure subset runtimes, but one that can be overridden is not.

# David-Sarah Hopwood (17 years ago)

David-Sarah Hopwood wrote:

Mark S. Miller wrote:

2009/2/10 Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com>

#2 Why allow "Object" for host objects that are required to conform to the section 15.3 specification for Object. If they are distinguishable from section 15.3 objects they should have [[Class]]=="Object". An implementation can use "HostObject" or something else. (Counter-argument: Might confuse some programmers??? (seems weak)) I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

Remember that, apart from algorithms that check whether [[Class]] is "Function", "Date" or "RegExp"

or "Array" [but that doesn't affect my point]

Note that the algorithms in the JSON section check whether [[Class]] is "Array" directly; they should probably be using Array.isArray.

# Mark S. Miller (17 years ago)

On Wed, Feb 11, 2009 at 8:27 AM, David-Sarah Hopwood < david.hopwood at industrial-designers.co.uk> wrote:

Note that the algorithms in the JSON section check whether [[Class]] is "Array" directly; they should probably be using Array.isArray.

Why? If someone assigns a different function to Array.isArray, should that change JSON's behavior? If instead we spec JSON to use the original value of Array.isArray, that's essentially the same thing as specing a [[Class]] check. Just specing the [[Class]] check is simpler and more direct.

# Allen Wirfs-Brock (17 years ago)

-----Original Message----- David-Sarah Hopwood wrote: ..

or "Array" [but that doesn't affect my point]

Note that the algorithms in the JSON section check whether [[Class]] is "Array" directly; they should probably be using Array.isArray.

Actually, it is probably better for algorithms to directly check, rather than invoke the user level Array.isArray function. The latter is a "up call" within the implementation layers. If the [[Class]]== 'Array' check was done a lot and was too verbose then an specification function could be defined for it. That specification function should then be used to specify Array.isArray.

# Allen Wirfs-Brock (17 years ago)

You're right. Too many different browsers open at the same time. It was probably FF and one of the other I looked at and I didn't look at any prototypes.

Regarding, IE I have no issues with IE being initially incompatible with ES3.1 in this regard. It's a low impact nonconformance and nothing in the ES3.1 specification actually tests [[Class]]=="Object". However, making it clear in ES3.1 that DOM (I really mean host) objects shouldn't claim to be "Object" (unless they really are) will provide an added incentive for IE to eventually conform.

Allen

From: Juriy Zaytsev [mailto:kangax at gmail.com] Sent: Tuesday, February 10, 2009 10:12 PM To: Allen Wirfs-Brock Cc: Mark S. Miller; Brendan Eich; Mark Miller; es-discuss Subject: Re: [[Class]] and host objects

On Feb 10, 2009, at 9:15 PM, Allen Wirfs-Brock wrote:

Mark Miller: I like your #2 direction a lot. If it were feasible to require that host objects not even use [[Class]] "Object", I'd be in favor. However, I'm guessing that would differ too greatly from current browser behavior to have a chance.

That's what I thought until I probed around a few DOM objects in IE and Firefox and didn't see any [object "Object"]'s. We probably need the browser experts to tells whether or not it is common practice to use [[Class]]=="Object" for host objects but a casual inspection looked promising.

I actually see IE6 and 7 having "Object" for most of the host methods' [[Class]]'es. I couldn't find any "Object" [[Class]] nether in FF nor in Gecko. Both, Opera (9.61) and Chrome (1.x) return "Object" for Element.prototype

[...]

-- Juriy Zaytsev

# Mark S. Miller (17 years ago)

Since FF, Opera, and Safari already conform, and since you folks are the MS representatives, it seems we have a winner! Let's go with the stronger language.