I made two arrays, each with 1 million items:
a1 = 1_000_000.times.to_a a2 = a1.clone
I tried to push a2 into a1:
a1.push *a2
This returns SystemStackError: stack level too deep
.
However, when I try with concat
, I don't get the error:
a1.concat a2 a1.length # => 2_000_000
I also don't get the error with the splat operator:
a3 = [*a1, *a2] a3.length # => 2_000_000
Why is this the case? I looked at the documentation for Array#push
, and it is written in C. I suspect that it may be doing some recursion under the hood, and that's why it's causing this error for large arrays. Is this correct? Is it not a good idea to use push
for large arrays?
An array is a data structure, which can store a fixed-size collection of elements of the same data type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type.
An array is a collection of similar types of data. For example, if we want to store the names of 100 people then we can create an array of the string type that can store 100 names. String[] array = new String[100];
There are three different kinds of arrays: indexed arrays, multidimensional arrays, and associative arrays.
An array type is a user-defined data type consisting of an ordered set of elements of a single data type. An ordinary array type has a defined upper bound on the number of elements and uses the ordinal position as the array index.
I think that this is not a recursion error, but an argument stack error. You are running up against the limit of the Ruby VM stack depth for arguments.
The problem is the splat operator, which is passed as an argument to push
. The splat operator is expanded into a million element argument list for push
.
As function arguments are passed as stack elements, and the pre-configured max size of the Ruby VM stack size is:
RubyVM::DEFAULT_PARAMS[:thread_vm_stack_size] => 1048576
..this is where the limit comes from.
You can try the following:
RUBY_THREAD_VM_STACK_SIZE=10000000 ruby array_script.rb
..and it will work fine.
This is also the reason you want to use concat
instead, as the whole array can be passed as one single reference, and concat
will then process the array internally. As opposed to push
+ splat, which will try to use the stack as a temporary storage for all the array elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With