Bug 181011 - JavaScript subclasses of typed arrays produce incorrect type when .of() is called
Summary: JavaScript subclasses of typed arrays produce incorrect type when .of() is ca...
Status: RESOLVED DUPLICATE of bug 216991
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: Safari 11
Hardware: iPhone / iPad iOS 11
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-12-19 16:40 PST by garett.ridge
Modified: 2020-10-18 14:45 PDT (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description garett.ridge 2017-12-19 16:40:56 PST
I show a very small demo of this bug here:

https://jsfiddle.net/dumb_lowtax/4pfn6e6L/

The short snippet there outputs a different result on iPhones and iPads than everywhere else.  It tries subclassing Float32Array and adding to it a method called "times()" for multiplying by a scalar.  This custom method comes up as undefined when using iOS.  In practice this means that my WebGL game engine works on all platforms except Apple, where all the basic vector types don't work.

The snippet helpfully logs the result of "v instanceof Vec" where Vec extends a typed array and v was created with .of(). That too shows different results only on those devices, exposing the root problem.  The built in of() functionality is returning type Float32Array instead of Vec.  Hovering over the variable in Web Inspector corroborates this.

Weirdness that I've experienced in the past with subclassing the typed arrays and getting unexpected behavior is already the reason I'm having to use "Vec.of( 1,2,3 )" everywhere, instead of just saying "new Vec( 1,2,3 )".
Comment 1 garett.ridge 2018-04-14 12:19:43 PDT
Discovered this breaks from() as well.

Basically, TypedArray.from() and TypedArray.of() are broken if you subclass a TypedArray.

It may be seen as uncommon to extend these built-in-types, but it intuitively seems like you should be able to, for example to add functionality like vector math to Float32Arrays.  That's extremely useful for a number of reasons.  When I did this to my WebGL framework it sped up my ray tracing demos by nearly an order of magnitude to with extending plain Arrays.  

Other options do not look so good.  Making a vector class wrap/contain a TypedArray instead of extending Float32Array outright is significantly less useful, since you no longer can use square bracket syntax, and since you'd have to also wrap every individual method of Array that you'd like to expose, in what would otherwise be a very short class (vector math is otherwise very short to implement due to es6 syntax and Array.map()).

When you extend TypedArray, the way it's built practically forces you to use .of() and .from() for everything so I imagine this bug will be hit frequently.  That's because the constructor of TypedArray is inconvenient; unlike Array, you cannot instantiate a filled Float32Array by just passing in the elements (if you have more than one) like "new Vector( 0, 0, 1 )".  This constructor does not exist like for Array counterparts.  You'll instead get a Float32Array of size 0.  The only way to declare vectors is then to either pass an array literal like "new Vector( [ 0, 0, 1 ] )" every time which is messier, or to use Vec.of() instead.

For now I have added a workaround to my framework for iOS by detecting the type of a subclass of Float32Array and then overriding of() and from() if necessary.  

This is an unfortunate workaround, since it measurably slows down my demo by a factor of 5 times.  If this bug in Safari were addressed, I could avoid that and my application would be able to run without such a drastic, unnecessary slowdown on phones.
Comment 2 garett.ridge 2018-04-14 12:22:10 PDT
*order of magnitude compared to
Comment 3 Alexey Shvayka 2020-10-18 14:45:14 PDT
(In reply to garett.ridge from comment #0)
> https://jsfiddle.net/dumb_lowtax/4pfn6e6L/

Thank you for the nice test case and detailed fix motivation!
r267603 fixed %TypedArray%.{from,of} with subclasses, aligning snippet's output with Chrome & Firefox.

PS. You may find https://github.com/tc39/proposal-rm-builtin-subclassing interesting.

*** This bug has been marked as a duplicate of bug 216991 ***