Array Like Interface

# Garrett Smith (15 years ago)

One statement that comes up a lot on comp.lang.javascript is "don't trust host objects". There cases where [[ToBoolean]], [[Put]], and [[Get]] throws in IE, but also in Firefox where the property is implemented as a getter, with no setter.

The implementation is responsible for ensuring the successful outcome of performing an Array operation on a Host object. A common interface for Array generics define an expected behavior, making the outcome of array generic operations on Host objects more clearly defined (and hopefully more reliable).

An example of where it might be useful to use Array Generics on a host object:-

var items = list.getElementsByTagName("li"); items = Array.slice(hostObj);

Results in Error in IE. Too bad, because it would be really useful to sort, filter, map, or reverse those items.

It isn't a bug of IE, even though it might seem to be. The problem is that the operation may legally fail. ECMAScript 5 draft states:-

| Whether the slice function can be applied successfully | to a host object is implementation-dependent.

This seems to go against the nature of Section 4 of ES5 which states that host objects "provide certain properties that can be accessed and certain functions that can be called from an ECMAScript program."

Could it ECMAScript 5 further state:- "A host object may also implement interfaces that are compatible with interfaces defined herein."

Could ECMAScript 5 make it easier for the Host environment to define such interface?

  • and then go on to define a List interface (below), which has only the length, and [[Put]] and [[Get]] methods, but none of the Array.prototype methods?

I'm envisioning a scenario where ECMA defines a common interface for a "List" and a common Host array-like collection Interface that is predictably compatible.

In ECMA land, methods that take Array-like methods ("List") could make the outcome of attempts of using array-like Host objects more predictable (so one would know what would happen before calling slice.call(hostListObj)). Such interfaces would exist in ECMAScript and in any Host environment. It would be defined in a way that was simple, and clearly and predictably compatible (or incompatible). Such Interface doesn't exist yet.

In Host land, Array-like collections in browsers could include NodeList, StyleSheetList, CSSRuleList. The Host environment would have to define a separate interface for these guys, so NodeList and the others would extend (or implement) the Array-like "List." Implementations could implement this interface for their own interfaces that may be nonstandard, such as window.frames[1] (if that has not made it into Ian Hickson's HTML 5 yet).

This change to Host objects would not constrain or restrict the Host objects, but would instead define a smaller subset of collection-like behavior.

To define Interfaces that could be used for Array Like collection for Host objects (in web pages):-

List { attribute unsigned long length; [[Get]] [[Put]] }

and

UnmodifiableList extends List { [[Put]] raises exception / [[ThrowingPut]] in ECMA }

If ECMAScript Array were to implement a List interface and Web IDL[2] were to define a compatible interface, the Array generics could be expected to work on instances of the respective interfaces, provided the ability to determine if, in fact, the object in question implements that interface. Surely, it would be very nice to also have a built-in method by which to determine this, so that Host objects could then implement this behavior, and be tagged. For example:-

if(List.isList( unknownObject )) {

}

That way, you could use a Host object "List" instance as the thisArg to an ECMAScript method that expects an ECMAScript List instance which defines behavior on an ECMAScript "List" and (provided the interfaces were compatible) get an expected outcome.

ECMAScript should should define an array-like object Interface in one place. It should define a common Interface for Array.prototype, so that Array.prototype would fulfill that interface, and that any Host object that also wants to fulfill that interface can, too, and still be a Host object, not an Array. This change would not affect the behavior of current implementations; it would merely change the interface so that other specs for Host objects could define a compatible interface.

Garrett

[1]developer.mozilla.org/En/DOM:window.frames [2]dev.w3.org/2006/webapi/WebIDL/#indexed

# Ian Hickson (15 years ago)

On Thu, 14 May 2009, Garrett Smith wrote:

Implementations could implement this interface for their own interfaces that may be nonstandard, such as window.frames[1] (if that has not made it into Ian Hickson's HTML 5 yet).

window.frames === window and is defined here:

www.whatwg.org/specs/web-apps/current-work/#dom-frames, www.whatwg.org/specs/web-apps/current-work/#accessing

# Allen Wirfs-Brock (15 years ago)

The ES specification implicitly defines such an interface. It is essentially, the union of the requirements that an object must support if it is going to work correctly with the specified generic array methods. Those implicit requirements are fairly basic, but include the standard specified behavior of internal methods such as [[Put]] (without that assumption, the specified algorithms are meaningless).

There is nothing stopping HTML or WebIDL from specify an interface that fully conforms to this implicit "generic array" interface.

Note that the host object exceptions in the Es5 spec. permits, but do not require that hosts take liberties with the ES specified object semantics. In particular, there is no reason that a browser cannot implement DOM objects as "native objects" rather than "host objects". Nor, from an ES specification perspective, there is no particular reason that the ES binding of WebIDL should permit use of host object semantics (which pretty means unspecified) rather than native object semantics. However, those responsible for maintaining and incrementally evolving existing implementations probably would have a different take on this matter.

I'm not saying that there is no value in being more explicit about the actual requirements for an object to be a fully functional generic array-like object. However, for objects that conform to the requirements of "native objects" there no ambiguity about the implicit requirements. To me it seems that the issue is really more about whether you want to continue to allow the semantics of some or all DOM objects to arbitrarily deviate from the semantics of native ECMAScript objects.

# Brendan Eich (15 years ago)

On May 15, 2009, at 10:34 AM, Allen Wirfs-Brock wrote:

Note that the host object exceptions in the Es5 spec. permits, but
do not require that hosts take liberties with the ES specified
object semantics. In particular, there is no reason that a browser
cannot implement DOM objects as "native objects" rather than "host
objects".

This is what Gecko has done forever, likewise KHTML -> WebKit, AFAIK.

The only "host objects" in Mozilla code have been some LiveConnect
(Java <-> JS bridge) ones, but those are being replaced by "native

objects" too.

Nor, from an ES specification perspective, there is no particular
reason that the ES binding of WebIDL should permit use of host
object semantics (which pretty means unspecified) rather than native
object semantics. However, those responsible for maintaining and
incrementally evolving existing implementations probably would have
a different take on this matter.

Anyone working on IE care to comment here, or in a w3c public list? If
the latter, a folllowup giving a link to the thread here would be
appreciated.

# Garrett Smith (15 years ago)

On Fri, May 15, 2009 at 10:34 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com> wrote:

The ES specification implicitly defines such an interface.  It is essentially, the union of the requirements that an object must support if it is going to work correctly with the specified generic array methods.  Those implicit requirements are fairly basic, but include the standard specified behavior of internal methods such as [[Put]] (without that assumption, the specified algorithms are meaningless).

Right. The problem is that that implied interface is not fulfilled in a compatible way IE. IE has list-like host objects which do not work with Array generics, even though those objects appear to support [[Get]] and length. However, in some cases, IE will err with even a simple [[Get]] property access operation. The pragmatic advice that is concluded after making such observations is that same c.l.js mantra: "Don't trust host objects."

By having an explicit interface, instead of an implicit one, the hope is that browsers would see that and make their host objects have an interface that is predictably compatible.

There is nothing stopping HTML or WebIDL from specify an interface that fully conforms to this implicit "generic array" interface.

The Web IDL has IndexGetter and IndexSetter -- not quite interfaces, in a formal sense. The Web IDL calls these [[IndexGetter]] and [[IndexSetter]] -- not quite interfaces, in a formal sense. A type of object that has an index setter would also seem to need an index getter, and either would need a length, so two interfaces would seem to suffice.

Such interface(s) would be something of a tagging interface for a feature check that scripts for pages could use, which could encourage and would likely give rise to scripts performing stronger inferencial checks, instead of unrelatated inferences, such as the classic user agent sniff.

Note that the host object exceptions in the Es5 spec. permits, but do not require that hosts take liberties with the ES specified object semantics. In particular, there is no reason that a browser cannot implement DOM objects as "native objects" rather than "host objects". Nor, from an ES specification perspective, there is no particular reason that the ES binding of WebIDL should permit use of host object semantics (which pretty means unspecified) rather than native object semantics. However, those responsible for maintaining and incrementally evolving existing implementations probably would have a different take on this matter.

I'm not saying that there is no value in being more explicit about the actual requirements for an object to be a fully functional generic array-like object. However, for objects that conform to the requirements of "native objects" there no ambiguity about the implicit requirements. To me it seems that the issue is really more about whether you want to continue to allow the semantics of some or all DOM objects to arbitrarily deviate from the semantics of native ECMAScript objects.

Host objects currently behave in implementation-dependent manner. Nobody likes it, but that's the way it is. I do not think such "implementation dependent" behavior should be arbitrary. I would very much like to have a way to determine the outcome of calling Array.prototype.slice.call( hostObject ); That would ensure that scripts can be backwards and forwards compatible without version checks, opt-in versioning, or unrelated inferences.

# Allen Wirfs-Brock (15 years ago)

-----Original Message----- From: Garrett Smith [mailto:dhtmlkitchen at gmail.com]

Right. The problem is that that implied interface is not fulfilled in a compatible way IE. IE has list-like host objects which do not work with Array generics, even though those objects appear to support [[Get]] and length. However, in some cases, IE will err with even a simple [[Get]] property access operation. The pragmatic advice that is concluded after making such observations is that same c.l.js mantra: "Don't trust host objects."

So, if the problem is limited to IE then you should continue to convey that this is an issue to the Microsoft IE team. This thread is a good start at that.

By having an explicit interface, instead of an implicit one, the hope is that browsers would see that and make their host objects have an interface that is predictably compatible.

I'm probably repeating myself here, but an new interface is not necessary to make this requirement explicit. If you want (and can get agreement) for these objects to fully implement ECMAScript native object semantics then that is all you have to say in the WebIDL JavaScript binding specification.

...

Host objects currently behave in implementation-dependent manner. Nobody likes it, but that's the way it is. I do not think such "implementation dependent" behavior should be arbitrary. I would very much like to have a way to determine the outcome of calling Array.prototype.slice.call( hostObject ); That would ensure that scripts can be backwards and forwards compatible without version checks, opt-in versioning, or unrelated inferences.

Again repeating myself, specifying that these objects must support "native" rather than "host" object semantics would accomplish what you desire. Either specification approach is a change that you are going to have generate consensus around, first in a specification process and ultimately from implementers.

# Allen Wirfs-Brock (15 years ago)

(forwarding for Travis since his direct post bounced)

From: Travis Leithead Sent: Monday, May 18, 2009 10:28 AM To: brendan at mozilla.com; Allen Wirfs-Brock; cam at mcc.id.au Cc: es-discuss; Garrett Smith; Chris Wilson Subject: Re: Array Like Interface

(Adding Cameron, the WebIDL editor)

Anyone working on IE care to comment here, or in a w3c public list? If the latter, a folllowup giving a link to the thread here would be appreciated.

Regarding whether we'd have a different take on the matter: we recognize that first and foremost, web developers want and need consistency in their experiences in cross-browser coding. It makes a lot of sense to implement DOM APIs, etc., as native objects because that gives web developers the best seamless JavaScript->DOM experience. Deviations, as Garrett has pointed out in a previous message, lead to the perception of a bug in the implementation.

IE does not implement the DOM as native JS objects, but as host objects. Therefore we depend heavily on specifications like WebIDL to help formalize what the mappings look like from COM to JavaScript. I don't know (or can't yet disclose ;) what the future will hold as far as our binding is concerned, but our ultimate goal is interoperability in this space, and this area has been a trouble-spot for interoperability in the past. I believe that WebIDL will go a long way toward reducing web dev pain as it is properly implemented.

WebIDL provides a logical and predictable JavaScript binding for the DOM. In my opinion, there are only a few places where it needs a bit more clarity:

  •    The List bindings (called sequence<T> in the spec, of which the author acknowledges that this needs some work (http://dev.w3.org/2006/webapi/WebIDL/#es-sequence). If implementations are allowed to start converting various NodeLists or NamedNodeMaps, etc. to Arrays, then what does a [[Put]] mean? Where would it go? Because many of the lists in the DOM are "live", a [[Put]] would be strange. It doesn't seem natural to use a linear model and automatically map it back to a tree model, because there's just not enough context to do that in the linear model. Of course, given the proper restrictions, I suppose a mapping could be worked out. I don't know how many of the Array-generics would make sense for various DOM collections. My instinct tells me that one-size does not fit all.
    
  •    New ES5 concepts.
    

o Now that ES5 is moving closer to standardization, WebIDL needs to consider the new ES5 concepts and how they should be mapped to DOM standards. For example, are there certain DOM objects that need to be considered "sealed" or "frozen"?

o How should object properties be represented; as data or accessor properties, or as a combination of both? IE8 took the route of consistency and made every property of the DOM an accessor property (which was natural, since the COM binding is a set of get/set pairs anyway), however, I'm not sure if this is needed as the default for many simple properties like element.id for instance.