4

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
Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107
Jeremy Smith
  • 14,727
  • 19
  • 67
  • 114

2 Answers2

2

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.)

thomthom
  • 2,854
  • 1
  • 23
  • 53
0

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.

Jeremy Smith
  • 14,727
  • 19
  • 67
  • 114
  • It's because the array you created in C was empty - it was just allocated memory for 4 items. It's incremented because you populated it. More details in the answer I posted. – thomthom Mar 19 '12 at 13:47