Jeremy Smith
Jeremy Smith

Reputation: 15069

Why is RARRAY_LEN not being allocated?

I'm using the C extension methods to create a new ruby array, but RARRAY_LEN is not getting set. Am I doing something wrong?

long int max = 4;
VALUE rAry;

rAry = rb_ary_new2(max);
printf("allocated: %lu\n", RARRAY_LEN(rAry));

output:

allocated: 0

Upvotes: 4

Views: 765

Answers (2)

thomthom
thomthom

Reputation: 2914

From array.c (Ruby 1.8.6): #define RARRAY_LEN(s) (RARRAY(s)->len)

RARRAY(s)->len is the same as Array#length.

rb_ary_new2(4) is not the same as Array.new(4).

VALUE
rb_ary_new2(len)
    long len;
{
    return ary_new(rb_cArray, len);
}

VALUE
rb_ary_new()
{
    return rb_ary_new2(ARY_DEFAULT_SIZE);
}

ARY_DEFAULT_SIZE is defined as 16.

What is does is just allocate memory for an array - but doesn't populate it. Use it when you know the final size of your array so it doesn't have to be dynamically re-sized.

What you want to use for your intentions are rb_ary_new3 or rb_ary_new4.

From Programming Ruby: The Pragmatic Programmer's Guide:

VALUE rb_ary_new3(long length, ...")
Returns a new Array of the given length and populated with the remaining arguments.

VALUE rb_ary_new4(long length, VALUE *values")
Returns a new Array of the given length and populated with the C array values.

Note that these functions require you to provide a value for each element. So you'd need to do something like: rAry = rb_ary_new3(4, Qnil, Qnil, Qnil, Qnil) to replicate Array.new(4). If you provided less arguments you'd get strange behavior in Ruby. (No exceptions - despite the fact you get an invalid object.)

Upvotes: 2

Jeremy Smith
Jeremy Smith

Reputation: 15069

Apparently rb_ary_store(obj, index, val) needs to be used to increment RARRAY_LEN. It's strange that a method so crucial is basically undocumented.

Upvotes: 0

Related Questions