Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clone new Array(number); #3364

Open
aboveyunhai opened this issue Mar 30, 2023 · 4 comments
Open

clone new Array(number); #3364

aboveyunhai opened this issue Mar 30, 2023 · 4 comments

Comments

@aboveyunhai
Copy link

aboveyunhai commented Mar 30, 2023

I realized that ramda will remove all value from the new Array initialization with predefine size, is this intentional?

const data = new Array(5);

console.log(data); // [undefined, undefined, undefined, undefined, undefined] , length: 5
console.log(Ramda.clone(data));
console.log(result); // [] length: 0
 

as oppose to Lodash

console.log(data); // [undefined, undefined, undefined, undefined, undefined] , length: 5
console.log(Lodash.clone(data));
console.log(result); // [undefined, undefined, undefined, undefined, undefined] , length: 5
@Harris-Miller
Copy link
Contributor

Welcome to the wonderful world of javascript!

Kidding aside. The behavior of new Array(x) is very often misunderstood. new Array(5) effectively creates { length: 5 } with prototypeOf Array. This is different from new Array(5).fill(undefined) that would be { 0: undefined, 1: undefined, 2: undefined, 3: undefined, 4: undefined, 5: undefined, length: 5 }

console.log(new Array(5).fill(undefined)) // [undefined, undefined, undefined, undefined, undefined] , length: 5

The way that Ramda clones arrays is by starting with an empty array and cloning each ownProperties's value from the original value over to it. The problem with this implementation is that for new Array(5), there are no ownProperties (The length property is non-enumerable).

This means that you put in an Array of length 5, and get out an Array of length 0. However, both the input and output array are still technically empty.

In general, we get a lot of variety on if [] === new Array(5) with respect to how length: 5 is treated when there are no keys

const data = new Array(5);

R.equals([], data); // true
lodash.isEqual([], data)); // false

data[0]; // undefined for `0` or any index
[...data]; // [undefined, undefined, undefined, undefined, undefined] , length: 5
Array.from(data); // [undefined, undefined, undefined, undefined, undefined] , length: 5

Obect.keys(data); // []
data.forEach(v => console.log(v)); // noop
for (let i; i <= data.length; i++) console.log(data[i]); // `undefined` x5
for (const key in data) console.log(key); // noop
for (const value of data) console.log(value); // // `undefined` x5

console.log(structuredClone(new Array(5))); // [] , length: 5

The question is: do we respect the value of the length property over the actual existance of the array?

My vote would be to do what structuredClone does here. because that would mean for all the operations shown above for a new Array(5), would give the exact same behavior using if used again with clone(new Array(5)) (not the current behavior, be aware, we'd change it to that)

This would simply mean, instead of starting the clone with an empty array [], we'd start it with new Array(originalArray.length)

@aboveyunhai
Copy link
Author

aboveyunhai commented Apr 4, 2023

@Harris-Miller wow thx, didn't expect such a comment with good educational materials.
Just an unrelated question based on your explanation, if that's how our ugly JavaScript :p Array(size) initializes the array with a given length without empty value, will it still have any performance gain?
Because in other languages generally if you pre-define size of an array, it will usually have some performance gain comparing to dynamic size since the address is continuous.

I wonder does javascript still handle it internally and correctly like other langs but with that quirky behavior, or it's just the same as dynamic array new array()?

@Harris-Miller
Copy link
Contributor

I wonder does javascript still handle it internally and correctly like other langs but with that quirky behavior, or it's just the same as dynamic array new array()?

According to this stack overflow post, it does matter

@Harris-Miller
Copy link
Contributor

@CrossEye @kedashoe @adispring This is a worth-file micro-optimization for any point within ramda where we are creating a new array where the length is known ahead of time, clone, map, etc...

Looks like _map is already doing this, we could do it in _clone as well:

// _clone.js
// is
case 'Array':   return copy([]);
// could be
case 'Array':   return copy(Array(value.length));

I'm sure there are other locations as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants