Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does 'array[array.length - 1] = array.pop()' yield undefined behavior?

I've been trying to implement a method which takes an array and an index as input, copies the last element of the given array into the entry at the given index, and then truncates the last element (i.e., sets the array shorter by one).

Here is the function which I was given as a suggestion for this task:

function swapWithLastAndRemove(array, index) {
    array[index] = array.pop();
}

I then tested this function to make sure that it works on any given index:

for (let index = 0; index < 5; index++) {
    var array = [0, 1, 2, 3, 4];
    swapWithLastAndRemove(array, index);
    console.log(array);
}

And I found it that it works correctly for all but the last index:

[ 4, 1, 2, 3 ]
[ 0, 4, 2, 3 ]
[ 0, 1, 4, 3 ]
[ 0, 1, 2, 4 ]
[ 0, 1, 2, 3, 4 ]

In other words, for the last element, it pops it out of the array, but then rewrites it into the array.

What strikes me, is that this line:

array[index] = array.pop();

Which is equivalent to this line when executed on the last element:

array[array.length - 1] = array.pop();

Could not have possibly resulted with the contents of array being equal to [ 0, 1, 2, 3, 4 ].

The way I see it, there are two options here:

  1. The statement array.pop() is executed before the expression array.length - 1 is evaluated
  2. The statement array.pop() is executed after the expression array.length - 1 is evaluated

In the first case, the contents of array would change as follows:

  • [ 0, 1, 2, 3, 4 ] // initial state
  • [ 0, 1, 2, 3 ] // after popping 4
  • [ 0, 1, 2, 4 ] // after assignment

In the second case, it should have triggered some sort of memory-access violation, because there would be an attempt to write into the 5th entry in the array (array[4]), when the length of the array is only 4 entries.

I know that NodeJS could be applying some memory-management scheme which would somehow allow this to complete without an "array index out of bound" exception, but I still don't get why it would let this operation "get away with it", and moreover, why the result is what it is.

Is the line array[array.length - 1] = array.pop() possibly undefined behavior?

Is there even such thing as undefined behavior in JavaScript?

like image 516
goodvibration Avatar asked Dec 04 '25 16:12

goodvibration


1 Answers

The second option: The statement array.pop() is executed after the expression array.length - 1 is evaluated

This is indeed what happens. JS evaluation is always left-to-right. It evaluates the array.length - 1 to index 4 of the array, then pops the last element from the array, then assigns that element to index 4.

In the second case, it should have triggered some sort of memory-access violation, because there would be an attempt to write into the 5th entry in the array (array[4]), when the length of the array is only 4 entries.

No, there are no memory access violations in JS. It just creates a new property again, and changes the length of the array accordingly. It's just the same as what happens with the code

const array = [0, 1, 2, 3, 4];
const element = array.pop();
console.log(JSON.stringify(array)); // [0,1,2,3]
array[4] = element;
console.log(JSON.stringify(array)); // [0,1,2,3,4]

Similarly, filling an array uses the same feature:

const array = [];
for (let i=0; i<5; i++)
    array[i] = i; // no memory access violation
console.log(array.length); // 5
like image 171
Bergi Avatar answered Dec 07 '25 05:12

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!