« All deprecation guides

Deprecation Guide for Deprecate array prototype extensions

until: 6.0.0
id: deprecate-array-prototype-extensions

Ember historically extended the prototypes of native Javascript arrays to implement Ember.Enumerable, Ember.MutableEnumerable, Ember.MutableArray, Ember.Array. As of v5, the usages of array prototype extensions are deprecated.

To disable the extention of array prototypes, in config/environment.js, ensure that EXTEND_PROTOYPES is set to false on EmberENV:

EmberENV: {  EXTEND_PROTOTYPES: false,  // ... }, // ...

Once it is set to false, audit your project for any breakage from the following methods no longer being available on native arrays. Exceptions will be thrown where they are in use:

For convenient functions like filterBy, compact, you can directly convert to use native array methods.

For mutation functions (like pushObject, replace) or observable properties (firstObject, lastObject), in order to keep the reactivity, you should take following steps:

  1. convert the array either to a new @tracked property, or use TrackedArray from tracked-built-ins;
  2. use array native methods;
  3. fully test to make sure the reactivity is maintained.

Convenient Functions

For convenient functions like filterBy, compact, you can directly convert to use native array methods. This includes following (a list from EmberArray methods):

any

Before:

someArray.any(callbackFn);

After:

someArray.some(callbackFn);

compact

Before:

someArray.compact();

After:

someArray = someArray.filter(val => val !== undefined && val !== null);

filterBy

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.filterBy('food', 'beans'); // [{ food: 'beans', isFruit: false }]

After:

let someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray = someArray.filter(el => el.food === 'beans'); // [{ food: 'beans', isFruit: false }]

findBy

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.findBy('isFruit'); // { food: 'apple', isFruit: true }

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.find(el => el.isFruit); // { food: 'apple', isFruit: true }

getEach

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.getEach('food'); // ['apple', 'beans']

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.map(el => el.food); // ['apple', 'beans']

invoke

Before:

class Person {  name;   constructor(name) {  this.name = name;  }   greet(prefix = 'Hello') {  return `${prefix} ${this.name}`;  } }  [new Person('Tom'), new Person('Joe')].invoke('greet', 'Hi'); // ['Hi Tom', 'Hi Joe']

After:

class Person {  name;   constructor(name) {  this.name = name;  }   greet(prefix = 'Hello') {  return `${prefix} ${this.name}`;  } }  [new Person('Tom'), new Person('Joe')].map(person => person['greet']?.('Hi')); // ['Hi Tom', 'Hi Joe']

isAny

Before

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.isAny('isFruit'); // true

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.some(el => el.isFruit); // true

isEvery

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.isEvery('isFruit'); // false

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.every(el => el.isFruit); // false

mapBy

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.mapBy('food'); // ['apple', 'beans']

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.map(el => el.food); // ['apple', 'beans']

objectAt

Before

const someArray = [1, 2, 3, undefined]; someArray.objectAt(1); // 2

After:

const someArray = [1, 2, 3, undefined]; someArray[1] // 2

objectsAt

Before:

const someArray = [1, 2, 3, undefined]; someArray.objectsAt([1, 2]); // [2, 3]

After:

const someArray = [1, 2, 3, undefined]; [1, 2].map(index => someArray[index]); //[2, 3]

reject

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.reject(el => el.isFruit); // [{ food: 'beans', isFruit: false }]

After:

let someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray = someArray.filter(el => !el.isFruit); // [{ food: 'beans', isFruit: false }]

rejectBy

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.rejectBy('isFruit'); // [{ food: 'beans', isFruit: false }]

After:

let someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray = someArray.filter(el => !el.isFruit); // [{ food: 'beans', isFruit: false }]

sortBy

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.sortBy('food', 'isFruit'); // [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; [...someArray].sort((a, b) => {  return a.food?.localeCompare(b.food)  ? a.food?.localeCompare(b.food)  : a.isFruit - b.isFruit; }); // [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]

toArray

Before:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; someArray.toArray(); // [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]

After:

const someArray = [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]; [...someArray] // [{ food: 'apple', isFruit: true }, { food: 'beans', isFruit: false }]

uniq

Before:

const someArray = [1, 2, 3, undefined, 3]; someArray.uniq(); // [1, 2, 3, undefined]

After:

const someArray = [1, 2, 3, undefined, 3]; [...new Set(someArray)] // [1, 2, 3, undefined]

uniqBy

Before:

const someArray = [{ food: 'apple' }, { food: 'beans' }, { food: 'apple' }]; someArray.uniqBy('food'); // [{ food: 'apple' }, { food: 'beans' }]

After:

const someArray = [{ food: 'apple' }, { food: 'beans' }, { food: 'apple' }]; someArray.reduce(  (unique, item) => {  if (!unique.find(i => item.food === i.food)) {  unique.push(item);  }  return unique;  },  [] ); // [{ food: 'apple' }, { food: 'beans' }]

You may also instead rely on methods from another library like lodash. Keep in mind that different libraries will behave in slightly different ways, so make sure any critical transformations are thoroughly tested.

Some special cases

without

Before

const someArray = ['a', 'b', 'c']; someArray.without('a'); // ['b', 'c']

After

let someArray = ['a', 'b', 'c']; someArray = someArray.filter(el => el !== 'a'); // ['b', 'c']

Please make sure without reactivity is fully tested.

setEach

setEach method internally implements set which responds to reactivity. You can either also use set or convert to @tracked properties.

Before

const items = [{ name: 'Joe' }, { name: 'Matt' }];  items.setEach('zipCode', '10011'); // items = [{ name: 'Joe', zipCode: '10011' }, { name: 'Matt', zipCode: '10011' }]

After

// use `set` import { set } from '@ember/object';  const items = [{ name: 'Joe' }, { name: 'Matt' }];  items.forEach(item => {  set(item, 'zipCode', '10011'); }); // items = [{ name: 'Joe', zipCode: '10011' }, { name: 'Matt', zipCode: '10011' }]

or

// use `@tracked` import { tracked } from '@glimmer/tracking';  class Person {  name;  @tracked zipCode;  constructor({ name, zipCode }) {  this.name = name;  this.zipCode = zipCode;  } }  const items = new TrackedArray([  new Person({ name: 'Joe' }),  new Person({ name: 'Matt' }), ]);  items.forEach(item => {  item.zipCode = '10011'; }); // items = [{ name: 'Joe', zipCode: '10011' }, { name: 'Matt', zipCode: '10011' }]

Observable Properties

firstObject, lastObject are observable properties. Changing directly from firstObject to at(0) or [0] might cause issues that the properties are no longer reactive.

Used in template

If the firstObject and lastObject are used in a template, you can convert to use get helper safely as get helper handles the reactivity already.

Before

<Foo @bar={{@list.firstObject.name}} />

After

<Foo @bar={{get @list '0.name'}} />

You can also leverage fixers provided by ember-template-lint/no-array-prototype-extensions.

Used in js

If the firstObject and lastObject are used in js files and you used them in an observable way, you will need to convert the accessors to @tracked array or TrackedArray.

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   // lastObj will change when `someAction` is executed  get lastObj() {  return this.abc.lastObject;  }   @action  someAction(value) {  this.abc.pushObject(value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   get lastObj() {  return this.abc.at(-1);  }   @action  someAction(value) {  this.abc.push(value);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = [];   get lastObj() {  return this.abc.at(-1);  }   @action  someAction(value) {  this.abc = [...this.abc, value];  } }

Mutation methods

Mutation methods are observable-based, which means you should always convert the accessors to @tracked or TrackedArray in order to maintain the reactivity. This includes following (a list from MutableArray methods):

addObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  addObject(value) {  this.abc.addObject(value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  addObject(value) {  if (!this.abc.includes(value)) {  this.abc.push(value);  }  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  addObject(value) {  if (!this.abc.includes(value)) {  this.abc = [...this.abc, value];  }  } }

addObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  addObjects(value) {  this.abc.addObjects(value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   _addObject(value) {  if (!this.abc.includes(value)) {  this.abc.push(value);  }  }   @action  addObjects(values) {  values.forEach(v => this._addObject(v))  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   _addObject(value) {  if (!this.abc.includes(value)) {  this.abc = [...this.abc, value];  }  }   @action  addObjects(values) {  values.forEach(v => this._addObject(v))  } }

clear

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  clear(value) {  this.abc.clear();  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  clear(value) {  this.abc.splice(0, this.abc.length);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  clear() {  this.abc = [];  } }

insertAt

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  insertAt(idx, value) {  this.abc.insertAt(idx, value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  insertAt(idx, value) {  this.abc.splice(idx, 0, value);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  insertAt(idx, value) {  this.abc = [...this.abc.slice(0, idx), value, this.abc.slice(this.abc.length - idx)]  } }

popObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  popObject() {  this.abc.popObject();  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  popObject() {  this.abc.pop();  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  popObject() {  this.abc.pop();  this.abc = [...this.abc];  } }

pushObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  pushObject(value) {  this.abc.pushObject(value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  pushObject(value) {  this.abc.push(value);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  pushObject(value) {  this.abc = [...this.abc, value];  } }

pushObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  pushObjects(values) {  this.abc.pushObjects(values);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  pushObjects(values) {  this.abc.push(...values);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  pushObjects(values) {  this.abc = [...this.abc, ...values];  } }

removeAt

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  removeAt(start, len) {  this.abc.removeAt(start, len);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  removeAt(start, len) {  this.abc.splice(start, len);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  removeAt(start, len) {  this.abc.splice(start, len);  this.abc = this.abc;  } }

removeObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  removeObject(value) {  this.abc.removeObject(value);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  removeObject(value) {  const index = this.abc.indexOf(value);  if (index !== -1) {  this.abc.splice(index, 1);  }  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  removeObject(value) {  let loc = this.abc.length || 0;  while (--loc >= 0) {  let curValue = this.abc.at(loc);   if (curValue === value) {  this.abc.splice(loc, 1);  }  }  this.abc = [...this.abc];  } }

removeObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  removeObjects(values) {  this.abc.removeObjects(values);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   _removeObject(value) {  let loc = this.abc.length || 0;  while (--loc >= 0) {  let curValue = this.abc.at(loc);   if (curValue === value) {  this.abc.splice(loc, 1);  }  }  }   @action  removeObjects(values) {  values.forEach(v => {  this._removeObject(v);  });  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   _removeObject(value) {  let loc = this.abc.length || 0;  while (--loc >= 0) {  let curValue = this.abc.at(loc);   if (curValue === value) {  this.abc.splice(loc, 1);  }  }  this.abc = [...this.abc];  }   @action  removeObjects(values) {  values.forEach(v => {  this._removeObject(v);  })  } }

replace

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  replace(idx, len, values) {  this.abc.replace(idx, len, values);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  replace(idx, len, values) {  this.abc.splice(idx, len, ...values);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  replace(idx, len, values) {  this.abc.splice(idx, len, ...values);  this.abc = [...this.abc];  } }

reverseObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  reverseObjects() {  this.abc.reverseObjects();  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  reverseObjects() {  this.abc.reverse();  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  reverseObjects() {  this.abc = [...this.abc.reverse()];  } }

setObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  setObjects(values) {  this.abc.setObjects(values);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  setObjects(values) {  this.abc.splice(0, this.abc.length, ...values);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  setObjects(values) {  this.abc = [...values];  } }

shiftObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  shiftObject() {  this.abc.shiftObject();  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  shiftObject() {  this.abc.shift();  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  shiftObject() {  this.abc.shift();  this.abc = [...this.abc]  } }

unshiftObject

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  unshiftObject(obj) {  this.abc.unshiftObject(obj);  } }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  unshiftObject(obj) {  this.abc.unshift(obj);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  unshiftObject(obj) {  this.abc.unshift(obj);  this.abc = [...this.abc];  } }

unshiftObjects

Before

import Component from '@glimmer/component'; export default class SampleComponent extends Component {  abc = ['x', 'y', 'z', 'x'];   @action  unshiftObjects(objs) {  this.abc.unshiftObjects(objs);  }

After

// TrackedArray import Component from '@glimmer/component'; import { action } from '@ember/object'; import { TrackedArray } from 'tracked-built-ins';  export default class SampleComponent extends Component {  abc = new TrackedArray(['x', 'y', 'z', 'x']);   @action  unshiftObjects(objs) {  this.abc.unshift(...objs);  } }

or

// @tracked import Component from '@glimmer/component'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking';  export default class SampleComponent extends Component {  @tracked abc = ['x', 'y', 'z', 'x'];   @action  unshiftObjects(objs) {  this.abc.unshift(...objs)  this.abc = [...this.abc];  } }

It's always recommended to reference the existing implementation of the method you are trying to convert. This can make sure functionalities are kept as it was. Implementation details can be found in MutableArray, for example removeObject.