Why does legacy content break when making array-likes real arrays?

# Domenic Denicola (8 years ago)

From: Anne van Kesteren

On Sun, Dec 30, 2012 at 10:22 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

  1. Array-like objects [not completely fixed (DOM...), but arguments

We've made some effort towards changing some of this, but legacy content is against us. :/

I saw this happen, and was sad, but never understood what the legacy problem was.

Similarly, when people ask me "why can't they just make arguments a real array" (perhaps with magic aliasing behavior in sloppy mode), I don't know the answer.

So just out of curiosity, how does legacy code break when making array-likes into real arrays? I feel like the Liskov Substitution Principle should have our back here.

# Anne van Kesteren (8 years ago)

On Sun, Dec 30, 2012 at 11:23 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

I saw this happen, and was sad, but never understood what the legacy problem was.

bugs.webkit.org/show_bug.cgi?id=81573

In particular bugs.webkit.org/show_bug.cgi?id=81573#c45

The problem with doing this for HTMLCollection is that HTMLCollection supports named properties. (No idea why that happened.) We could maybe have HTMLCollection.toArray() or some such at some point if that's found desirable. Haven't seen that many requests for such a thing yet.

# Brendan Eich (8 years ago)

Domenic Denicola wrote:

From: Anne van Kesteren

On Sun, Dec 30, 2012 at 10:22 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

  1. Array-like objects [not completely fixed (DOM...), but arguments We've made some effort towards changing some of this, but legacy content is against us. :/

I saw this happen, and was sad, but never understood what the legacy problem was.

Similarly, when people ask me "why can't they just make arguments a real array" (perhaps with magic aliasing behavior in sloppy mode), I don't know the answer.

So just out of curiosity, how does legacy code break when making array-likes into real arrays? I feel like the Liskov Substitution Principle should have our back here.

LSP is not magic. Works better when you have a type system.

The history of what went wrong is recorded here:

mail.mozilla.org/pipermail/es5-discuss/2009-August/003112.html

Read the followups. I'll cite Oliver's message in full below.


Problem with Arguments inheriting from Array

Oliver Hunt oliver at apple.com /Mon Aug 17 16:08:21 PDT 2009/

I implement the logic to make the Arguments object inherit from Array in WebKit last friday and it's quickly turned up a severe incompatibility with Prototype.js, specifcally Prototype's isArray function:

    isArray: function(object) {
      return object != null && typeof object == "object" &&
        'splice' in object && 'join' in object;
    }

This breaks at the very least a number of Apple sites and Nasa.gov -- that's just two of the top row of sites onhttp://www.prototypejs.org/real-world , other sites didn't appear to be broken but then i was merely looking at loading the front page, nothing more.

Unfortunately the use of 'in' means we also can't just shadow a less useful function with null or undefined for now.

Due to these site breakages, caused by a major compatibility problem in a fairly major library it seems infeasible to attempt to retrofit array like behaviour onto arguments.

--Oliver

# Erik Arvidsson (8 years ago)

The problem was code that incorrectly assumed instanceof to mean that the instance was an Array in combination with Array.prototype.concat.

There was a bug in Google's Closure Library which caused almost all Google's apps to fail due to this. The library was updated as soon as this was found but there might still be code out there that makes the same incorrect assumption in combination with concat.

I wanted to make another try under a runtime flag in Chromium but was blocked by Apple.

# Erik Arvidsson (8 years ago)

To clarify, my message was about making NodeList have Array.prototype in its prototype chain.

# Brandon Benvie (8 years ago)

The primary issue is that most array-likes aren't array-like when it comes to mutability. Most exposed indexed objects don't allow changes to their indices, which is decidedly un-array-like for ~quarter of array operations. It would be useful for there to be a separate "Indexed" class/prototype that contained the Array methods that don't mutate this, which Arguments and NodeLists and a bunch of other stuff could inherit from, which would also prevent backward compat issues with testing for instanceof Array.

# Erik Arvidsson (8 years ago)

On Sun, Dec 30, 2012 at 6:05 PM, Brandon Benvie <brandon at brandonbenvie.com> wrote:

The primary issue is that most array-likes aren't array-like when it comes to mutability. Most exposed indexed objects don't allow changes to their indices, which is decidedly un-array-like for ~quarter of array operations.

The issue is not about the mutation methods even though it is non sensical to call push on an immutable array.

It would be useful for there to be a separate "Indexed" class/prototype that contained the Array methods that don't mutate this, which Arguments and NodeLists and a bunch of other stuff could inherit from, which would also prevent backward compat issues with testing for instanceof Array.

That would not help in the case with NodeList. The fix there would be to have concat not do a brand check on its arguments. Allen has outlined the problematic brand checks at strawman:es5_internal_nominal_typing

# Brandon Benvie (8 years ago)

True, concat specifically needs to be changed. But it is the only Array method that does that check (the only other internal checks for brand BuiltinArray are in apply and isArray I think).

# Allen Wirfs-Brock (8 years ago)

On Dec 31, 2012, at 10:39 AM, Brandon Benvie wrote:

True, concat specifically needs to be changed. But it is the only Array method that does that check (the only other internal checks for brand BuiltinArray are in apply and isArray I think).

In support of Array subclassing, I have a tweak to concat that allows properly formed subclasses of Array to use concat and produce subclass instances while still preserving the current behavior for existing us3w. I'll be ready to post the full details soon.

# Brandon Benvie (8 years ago)

The work so far in the spec on enabling subclassing has been awesome and I look forward to seeing this!