Object.prototype.toString.call(Uint8Array.prototype) throws a TypeError

# Jeff Walden (11 years ago)

Per latest draft, %TypedArray%.prototype[@@toStringTag] is a getter that throws a TypeError if |this| doesn't have the internal slots of a typed array. Neither %TypedArray%.prototype nor {{Ui,I}nt{8,16,32},Float{32,64}}.prototype have these internal slots. So the builtin Object toString method, called on any of these objects, will throw a TypeError. Is this wise? I suspect there's debugging code out there that expects that toString doesn't throw on at least the typed array prototypes (seeing as it doesn't throw in any engine I'm aware of right now, tho the returned string is inconsistent).

# Allen Wirfs-Brock (11 years ago)

On Aug 28, 2014, at 2:56 PM, Jeff Walden wrote:

Per latest draft, %TypedArray%.prototype[@@toStringTag] is a getter that throws a TypeError if |this| doesn't have the internal slots of a typed array. Neither %TypedArray%.prototype nor {{Ui,I}nt{8,16,32},Float{32,64}}.prototype have these internal slots. So the builtin Object toString method, called on any of these objects, will throw a TypeError. Is this wise? I suspect there's debugging code out there that expects that toString doesn't throw on at least the typed array prototypes (seeing as it doesn't throw in any engine I'm aware of right now, tho the returned string is inconsistent).

This seems like a special case of the general problem that methods, defined on prototype objects, that have dependencies upon instance state such as internal slots or exotic internal methods won't work if applied to their containing prototypes when those prototypes do not provide the expected instance state or behavior.

I don't think there is a general solution to this problem. It's a place where the ESs "class model" is a leaky abstraction.

As a special case solution (in support of universal toString support) we could make all such @@toStringTag getters all back to returning "Object" if the instance requirements they check for are not met.

I'd happily accept a bug on that.

In an earlier iteration of O.p.toString I was eating exceptions thrown when getting the @@toStringTag value. But that sort of exception suppression wasn't very well received.

# Andrea Giammarchi (11 years ago)

Wouldn't that be inconsistent with {}.toString.call(String.prototype) and all others ?

I'd personally expect {}.toString.call(new Float32Array([1,2,3])) to produce same result of {}.toString.call(Float32Array.prototype), seems like the "least surprise"

# Allen Wirfs-Brock (11 years ago)

On Aug 29, 2014, at 3:09 AM, Andrea Giammarchi wrote:

Wouldn't that be inconsistent with {}.toString.call(String.prototype) and all others ?

I'd personally expect {}.toString.call(new Float32Array([1,2,3])) to produce same result of {}.toString.call(Float32Array.prototype), seems like the "least surprise"

Why one is a TypedArray instance and the other is an ordinary object.

BTW, another way to approach this issue would be to include the equivalent of:

   if (this.constructor.prototype === this) return "Object"

in the @@toStringTag getter for such classes.

# Jason Orendorff (11 years ago)

On Fri, Aug 29, 2014 at 5:09 AM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:

Wouldn't that be inconsistent with {}.toString.call(String.prototype) and all others ?

It is inconsistent, but it's a change TC39 deliberately chose to take.

It's a good change. The fact that Date.prototype is a real Date object, for example, has been a common source of bugs and general weirdness.

# John-David Dalton (11 years ago)

JS libs/frameworks (jQuery, Dojo, Lo-Dash, Ember, Angular, ...) have settled on using Object.prototype.toString.call as a way to determine the kind of a value and don't expect that to throw. This is edge case but it seems like an unnecessary gotcha to throw at devs.

# Allen Wirfs-Brock (11 years ago)

On Aug 29, 2014, at 12:10 PM, John-David Dalton wrote:

JS libs/frameworks (jQuery, Dojo, Lo-Dash, Ember, Angular, ...) have settled on using Object.prototype.toString.call as a way to determine the kind of a value and don't expect that to throw. This is edge case but it seems like an unnecessary gotcha to throw at devs.

We've explicitly designed the ES6 O.p.toString to preserve the [[Class]] type branding that was proved by prior editions but also decided to explicitly not support any new primitive [[Class]]-like brand values. Going forward it isn't a reliable way to type check or brand new built-in or programmer defined "types".

I will fix the handful of standard @@toStringTag getters so they don't throw. But I can't really really do anything about user written @@toStringTag getter that throw or for that matter objects that use Proxies to throw.

So, unless you wan to argue for eating exceptions in O.P.toStringm, that possibility will remain but is likely the reflection of a bug or malicious code. Presumablly, such problems can be diagnosed via a debugger

# John-David Dalton (11 years ago)

I will fix the handful of standard @@toStringTag getters so they don't

throw

That's rad!

But I can't really really do anything about user written @@toStringTag

getter that throw or for that matter objects that use Proxies to throw.

Ya, that's fine.

# Andrea Giammarchi (11 years ago)

one is a TypedArray instance and the other is an ordinary object.

let me try again ...

Wouldn't that be inconsistent with {}.toString.call(String.prototype)

and all others ?

Isn't String.prototype an ordinary object ?

# Andrea Giammarchi (11 years ago)

in case my question wasn't clear ...

String.prototype instanceof String is false and typeof String.prototype is object

So, my concern, and the least surprise I was talking about, are still there. Feel free to ignore though

# Claude Pache (11 years ago)

Le 30 août 2014 à 00:12, Andrea Giammarchi <andrea.giammarchi at gmail.com> a écrit :

Isn't String.prototype an ordinary object ?

In ES1-5, String.prototype is a real String object, that wraps the empty string [1], and it is implemented as such in current browsers. But, this is intended to be changed in ES6 [2], and the result of Object.prototype.toString.call(String.prototype) shall change accordingly.

[1] www.ecma-international.org/ecma-262/5.1/#sec-15.5.4 [2] people.mozilla.org/~jorendorff/es6-draft.html#sec

# Andrea Giammarchi (11 years ago)

I see, thanks for clarification.

If all native constructors will return [object Object] then it's OK for Float32Array.prototype and others to return the same but I'd rather avoid throwing with the most universally recognized as safe way to grab generic variables [[Class]]