Based on browsing the Ruby API sources for Array#length and Range#begin I know that macros RARRAY_LEN and RANGE_BEG exist and are used to implement the corresponding methods:
Array#length
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
}
Range#begin
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
However, while the code below has no problems with RARRAY_LEN I have been unable to get RANGE_BEG to work:
test.c
#include "test.h"
VALUE rb_mTest = Qnil;
VALUE rb_cTest = Qnil;
VALUE super_initialize(VALUE self) {
return self;
}
VALUE array_len(VALUE self, VALUE ary) {
Check_Type(ary, T_ARRAY);
return LONG2NUM(RARRAY_LEN(ary)); // this works
}
VALUE range_begin(VALUE self, VALUE rng) {
if (rb_obj_is_kind_of(rng, rb_cRange)) {
// return RANGE_BEG(rng); // doesn't work
return rb_funcall(rng, rb_intern("begin"), 0); // this works
}
return Qnil;
}
void Init_test(void) {
rb_mTest = rb_define_module("RangeTest");
rb_cTest = rb_define_class_under(rb_mTest, "Tester", rb_cObject);
rb_define_method(rb_cTest, "initialize", super_initialize, 0);
rb_define_method(rb_cTest, "array_len", array_len, 1);
rb_define_method(rb_cTest, "begin_value", range_begin, 1);
}
test.h
#ifndef TEST_H
#define TEST_H 1
#include "ruby.h"
VALUE super_initialize(VALUE self);
void Init_test(void);
VALUE range_begin(VALUE self, VALUE rng);
VALUE array_len(VALUE self, VALUE ary);
#endif /* TEST_H */
When the commented line is made active, the compiler generates this error message:
error: implicit declaration of function 'RANGE_BEG' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return RANGE_BEG(rng);
^
1 error generated.
This sounds to me like I'm missing an include, but 1) no additional include is required for RARRAY_LEN; 2) including range.h didn't change anything; and 3) I've failed to find where RANGE_BEG is defined when I tried searching with grep.
As you can see, I have a work-around using rb_funcall but would like to know why one macro found in the Ruby source works while another doesn't. The extension docs I've looked at have also implied that the macro versions are more efficient than function call versions for data access, so using the macro would be preferable.
To sum up, I'm hoping anybody can tell me a suitable incantation to get the compiler to access RANGE_BEG. This is happening on MacOS 12.4 (Monterey) using ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21] installed by HomeBrew, with CPPFLAGS=-I/opt/homebrew/opt/ruby/include and LDFLAGS=-L/opt/homebrew/opt/ruby/lib.