Exotic OBJECT?

# Garrett Smith (10 years ago)

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

Firefox 31: typeof document.createElement("object") "function" Function.prototype.toString.call(document.createElement("object")); TypeError: Function.prototype.toString called on incompatible object

If the typeof OBJECT results "function" then it either: a) implements [[Call]] or b) is exotic

Since calling Function.prototype.toString with OBJECT as the this value results in a TypeError, it appears that the OBJECT does not implement [[Call]] and thus the only explanation is that the OBJECT is exotic. Did I get that right? Or is there another explanation?

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

# Claude Pache (10 years ago)

According to comments 10-18 in bugzilla.mozilla.org/show_bug.cgi?id=268945 , object and embed elements do implement [[Call]] for some obscure reason. Hence typeof yielding "function".

Maybe I'm splitting hairs, but the spec doesn't say explicitly that all objects implementing [[Call]] must support Function.prototype.toString, although I'm not sure that that omission was intentional. Anyway, if you want to test if an object implements [[Call]], the best method is simply to try to call it:

document.createElement("object")()

(which produces an interesting result in Firefox).

# Garrett Smith (10 years ago)

Calling the OBJECT here does not result in a TypeError. If it were not callable, then TypeError would have to be the result.

Thus, the OBJECT implements [[Call]]. Furthermore, the ReferenceError that is thrown as a result of calling Function.prototype.toString on that OBJECT is not explained by the OBJECT not implementing call.

To test if a function implements [[Call]], use the typeof operator.

# Allen Wirfs-Brock (10 years ago)

On Aug 12, 2014, at 9:44 AM, Garrett Smith wrote:

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

Firefox 31: typeof document.createElement("object") "function" Function.prototype.toString.call(document.createElement("object")); TypeError: Function.prototype.toString called on incompatible object

If the typeof OBJECT results "function" then it either: a) implements [[Call]] or b) is exotic

Since calling Function.prototype.toString with OBJECT as the this value results in a TypeError, it appears that the OBJECT does not implement [[Call]] and thus the only explanation is that the OBJECT is exotic. Did I get that right? Or is there another explanation?

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

I don't see any where in your test where you [[Call]] OBJECT.

You [[Call]] Function.prototype.toString with OBJECT passed as the this value.

The ES5 spec. clearly says that F.p.toString is called with a this value that is not a "Function object". Note this usage of "Function object" means an actual instance of the built-in Function constructor and not the more general, any object that isCallable.

So, this is exactly the behavior I would expect if OBJECT is some sort of exotic callable that is not actually an instance of Function.

# Garrett Smith (10 years ago)

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Allen -

On Aug 12, 2014, at 9:44 AM, Garrett Smith wrote:

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

Firefox 31: typeof document.createElement("object") "function" Function.prototype.toString.call(document.createElement("object")); TypeError: Function.prototype.toString called on incompatible object

If the typeof OBJECT results "function" then it either: a) implements [[Call]] or b) is exotic

Since calling Function.prototype.toString with OBJECT as the this value results in a TypeError, it appears that the OBJECT does not implement [[Call]] and thus the only explanation is that the OBJECT is exotic. Did I get that right? Or is there another explanation?

I based this conclusion off of the latest ES6 draft, at: people.mozilla.org/~jorendorff/es6-draft.html#sec-function.prototype.tostring

"throws a TypeError exception if its this value does not have a [[Call]] internal method"

What's the explanation and reason for this strange characteristic of the OBJECT element in Firefox?

I don't see any where in your test where you [[Call]] OBJECT.

I tested the typeof operator to see if the OBJECT implements [[Call]] by using typeof. The result was "function". Please go back and read all replies.

You [[Call]] Function.prototype.toString with OBJECT passed as the this value.

The ES5 spec. clearly says that F.p.toString is called with a this value that is not a "Function object". Note this usage of "Function object" means an actual instance of the built-in Function constructor and not the more general, any object that isCallable.

ES5, in a few places, vascillates between the terms "function object" and isCallable. E.g. "When the [[Call]] internal method for a Function object..." yet there is no description of what happens when [[Call]] is called on any object that implements [[Call]] but is not a function (non-function host objects). Such objects not only exist but are mentioned under the definition of the typeof operator:-

Object (implements [[Call]]) "function

There is also the failure of ES5 to differentiate between the two types of host objects: native, and non-native, as I brought up and as we discussed over 4 years ago. This differentiation is explained in the ES6 draft as "exotic objects".

The ES6 replaces "function object" with "isCallable" and "implements [[Call]]" in many places, and the place that is of concern here is the description of Function.prototype.toString:

| Function.prototype.toString | ... | | The toString function is not generic; it throws a | TypeError exception if its this value does not have | a [[Call]] internal method. Therefore, it cannot be | transferred to other kinds of objects for use as a method.

Do you agree or disagree with the fact that the OBJECT implements [[Call]]? And if you disagree, please explain.

Are you proposing that the definition of Function.prototype.toString needs to be reverted to once again use "function object"? If not, what is your proposal?

# Allen Wirfs-Brock (10 years ago)

On Aug 12, 2014, at 2:17 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Since calling Function.prototype.toString with OBJECT as the this value results in a TypeError, it appears that the OBJECT does not implement [[Call]] and thus the only explanation is that the OBJECT is exotic. Did I get that right? Or is there another explanation?

I based this conclusion off of the latest ES6 draft, at: people.mozilla.org/~jorendorff/es6-draft.html#sec-function.prototype.tostring

"throws a TypeError exception if its this value does not have a [[Call]] internal method"

Hmm, that's a change from the ES5 spec. (which is what I would optimsitically hope browsers now support). I also thing that change is a bug that needs to be reverted. Function.prototype.toString does things that requires intimate knowledge of the internal structure of its this value. I don't see how it could possibly workk for any possible object with a [[Call]] internal method.

... The ES5 spec. clearly says that F.p.toString is called with a this value that is not a "Function object". Note this usage of "Function object" means an actual instance of the built-in Function constructor and not the more general, any object that isCallable.

ES5, in a few places, vascillates between the terms "function object"

but, not that in F.p.toString it is capital-F "Function object" and that has a specific meaning.

and isCallable. E.g. "When the [[Call]] internal method for a Function object..." yet there is no description of what happens when [[Call]] is called on any object that implements [[Call]] but is not a function (non-function host objects). Such objects not only exist but are mentioned under the definition of the typeof operator:-

Object (implements [[Call]]) "function

There is also the failure of ES5 to differentiate between the two types of host objects: native, and non-native, as I brought up and as we discussed over 4 years ago. This differentiation is explained in the ES6 draft as "exotic objects".

right, all address in ES6

The ES6 replaces "function object" with "isCallable" and "implements [[Call]]" in many places, and the place that is of concern here is the description of Function.prototype.toString:

| Function.prototype.toString | ... | | The toString function is not generic; it throws a | TypeError exception if its this value does not have | a [[Call]] internal method. Therefore, it cannot be | transferred to other kinds of objects for use as a method.

This is a spec, bug. should probably be expressed as does not have a [[Code]] internal slot.

Do you agree or disagree with the fact that the OBJECT implements [[Call]]? And if you disagree, please explain.

Here is what my test shows in FF33: Function.prototype.call.call(document.createElement("object")) /* Exception: @Scratchpad/1:1:0 */

Function.prototype.call.call({}) /* Exception: Function.prototype.call called on incompatible Object @Scratchpad/1:2:1 */

Clearly, OBJECT is doing something different for [[Ca]] than what an ordinary object does.

Are you proposing that the definition of Function.prototype.toString needs to be reverted to once again use "function object"? If not, what is your proposal?

It would be "Function object", but that isn't precise enough. [[Code]] (the built-in function brand check) is what needs to be used.

# Garrett Smith (10 years ago)

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 2:17 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

[...]

| Function.prototype.toString | ... | | The toString function is not generic; it throws a | TypeError exception if its this value does not have | a [[Call]] internal method. Therefore, it cannot be | transferred to other kinds of objects for use as a method.

This is a spec, bug. should probably be expressed as does not have a [[Code]] internal slot.

What is the [[Code]] for host methods like addEventListener? And what is the expected result of addEventListener.toString()?

Spec for Function.prototype.toString has never reflected reality for host methods.

Thanks.

# Allen Wirfs-Brock (10 years ago)

On Aug 12, 2014, at 7:52 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 2:17 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

[...]

| Function.prototype.toString | ... | | The toString function is not generic; it throws a | TypeError exception if its this value does not have | a [[Call]] internal method. Therefore, it cannot be | transferred to other kinds of objects for use as a method.

This is a spec, bug. should probably be expressed as does not have a [[Code]] internal slot.

What is the [[Code]] for host methods like addEventListener? And what is the expected result of addEventListener.toString()?

Spec for Function.prototype.toString has never reflected reality for host methods.

Tweaking spec. text as we go. The guard is actually going to be: either has a [[Code]] internal slot or is a Built-in function object (see people.mozilla.org/~jorendorff/es6-draft.html#sec-built-in-function-objects ). Which is pretty much just a way of saying a function whose implementation details F.p.toString understands.

As long as addEventListener is implemented as a built-in function (whatever that means for the implementation) then f.p.toString should be able to deal with it.

# Garrett Smith (10 years ago)

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 7:52 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 2:17 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

[...]

As long as addEventListener is implemented as a built-in function (whatever that means for the implementation) then f.p.toString should be able to deal with it.

Now "built in" is overloaded.

Built in objects are those which are supplied the ECMAScript implementation, independent of the host environment. A built in function is a built-in object that is a function.

Method addEventListener is supplied by the host environment and is therefore not a built-in function.

The new meaning for "built-in function" that you mention doesn't match the term defined earlier in the spec: "built in object."

"The built-in function objects defined in this specification may be implemented as either ECMAScript function objects (9.2) whose behaviour is provided using ECMAScript code or as implementation provided exotic function objects whose behaviour is provided in some other manner."

That looks like an attempt to describe functions that are implemented with native code, as described by CreateBuiltinFunction. CreateBuiltinFunction might be better named, such as CreateNativeFunction, to provide consistent, unambiguous terminology and which could also be used unambiguously for WebIDL platform objects.

# Allen Wirfs-Brock (10 years ago)

On Aug 13, 2014, at 8:46 AM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 7:52 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Aug 12, 2014, at 2:17 PM, Garrett Smith wrote:

On 8/12/14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

[...]

As long as addEventListener is implemented as a built-in function (whatever that means for the implementation) then f.p.toString should be able to deal with it.

Now "built in" is overloaded.

Built in objects are those which are supplied the ECMAScript implementation, independent of the host environment. A built in function is a built-in object that is a function.

Method addEventListener is supplied by the host environment and is therefore not a built-in function.

It's built-in to the complete environment provided by the host which includes the ES engine. For a host to provide such functions it has to have agreement with the ES engine on how to express and install them.

The new meaning for "built-in function" that you mention doesn't match the term defined earlier in the spec: "built in object."

In 4.3.6 the qualifier "independent of the host environment" probably needs to go away.

"The built-in function objects defined in this specification may be implemented as either ECMAScript function objects (9.2) whose behaviour is provided using ECMAScript code or as implementation provided exotic function objects whose behaviour is provided in some other manner."

That looks like an attempt to describe functions that are implemented with native code, as described by CreateBuiltinFunction. CreateBuiltinFunction might be better named, such as CreateNativeFunction, to provide consistent, unambiguous terminology and which could also be used unambiguously for WebIDL platform objects.

What's native code? It's up to the implementation to decide how built-in functions that aren't ECMAScript function objects are implemented. Maybe its all layered on top of some other virtual machine. "Native method" is a term that we have intentionally eliminated because of its high potential to carry unintended implications.

Similar, we eliminated the term "host method" because, from a semantic perspective, it doesn't matter if a method is provided by the ES engine or by the host using hooks provided by the ES engine. We don't want to imply that host-provided methods have any special semantic restrictions or capabilities..

# Boris Zbarsky (10 years ago)

On 8/12/14, 12:44 PM, Garrett Smith wrote:

If the typeof OBJECT results "function" then it either: a) implements [[Call]]

That's exactly what it does. This allows making plug-in objects callable if the plug-in decides to do so.

Since calling Function.prototype.toString with OBJECT as the this value results in a TypeError, it appears that the OBJECT does not implement [[Call]]

Nope. It definitely implements [[Cal]]; I can point you to the part of the code where that's done if you care.

The issue you're seeing is that in SpiderMonkey Function.prototype.toString will throw if its 'this' value is not a Function object (as defined based on internal [[Class]] like checks, not based on [[Call]]; in particular note that Object.prototype.toString does not return "Function" for an <object> in SpiderMonkey). So it

throws for various callables that aren't actually functions.