How to correctly create ruby objects from C extensions

Hello Group,

I'm asking myself what is the way to create a ruby object correctly from
a C extension. As I've extracted from ruby.h and README.EXT the things I
can come up with are:

rb_funcall(rb_const_get(self, rb_intern('Complex')), rb_intern('new'), 2, rb_float_new(real), rb_float_new(imag));
// which is impressively complicated and long.

rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

This seems to be really complicated just for wrapping my C complex
numbers into ruby Complex numbers.

So as I always have seen that things are easier in ruby, what should I
do?

Thanks a lot,

Brian

Hello Group,

I'm asking myself what is the way to create a ruby object correctly from
a C extension. As I've extracted from ruby.h and README.EXT the things I
can come up with are:

  See for example http://www.ruby-doc.org/doxygen/1.8.1/index.html

rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

  To get char* pointer from Ruby string,
    char *p;
    p = StringValuePtr(rubyString);
  To create Ruby string from C string,
    return rb_str_new( (char pointer), (length));
  or
    return rb_str_new2("a string");
  or with rb_str_new3(), 4(), 5() and other functions.

···

On Thu, 27 Jan 2005 23:52:48 +0900, Brian Schröder wrote:

Brian Schröder wrote:

Hello Group,

I'm asking myself what is the way to create a ruby object correctly

from

a C extension. As I've extracted from ruby.h and README.EXT the

things I

can come up with are:

rb_funcall(rb_const_get(self, rb_intern('Complex')),

rb_intern('new'), 2, rb_float_new(real), rb_float_new(imag));

// which is impressively complicated and long.

You could write a function like

/* initialize these static variables in your *_init() function */
static VALUE cComplex;
static ID id_new;

static VALUE
complex_new(double real, double imag)
{
return rb_funcall(cComplex, id_new, 2, rb_float_new(real),
rb_float_new(imag));
}

Since the complex class is implemented in ruby there is no
rb_complex_new().

rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

You can use the ruby string functions and then call
StringValueCStr(ruby_string).

This seems to be really complicated just for wrapping my C complex
numbers into ruby Complex numbers.

I think it would be nice if ruby had a COMPLEX_T - for both efficency
and for writing C extensions. On 64 bit systems it is easy to add
this, but on 32 bit systems it would increase the size of all ruby
objects unless you use a pointer to a second structure.
But, considering that even C has a built in complex type, I think it
would be worth while.

So as I always have seen that things are easier in ruby, what should

I

do?

Use ruby :wink:

-Charlie

Brian =?ISO-8859-15?Q?Schr=F6der?= writes:

> rb_eval_string(constructing_string)
> // Which is ugly because of eval and because of C string functions.

eval is nowhere near ugly, it's the best invention since sliced bread

Klaus Schilling

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below): "PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.

(This code is used for typemapping in SWIG/Python)
%typemap(out) Ptv_double& {
   Ptv_double& p= (*$1);
    int size = p.size();
    $result = PyList_New(size);
    for (int i=0; i<size; i++)
       PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));
}

Can anyone please help ?

</asbjørn>

The (roughly) equivalent code in a Ruby extension would be:

    $result = rb_ary_new2(size);
    for (int i = 0; i < size; i++)
        rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

Hope this helps,

Lyle

···

On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen <asbjoert@ifi.uio.no> wrote:

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below):
"PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.

Thank you Lyle !! It really helps. :slight_smile:
Think I am getting the hang of it now.

···

On Thu, 27 Jan 2005, Lyle Johnson wrote:

On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen > <asbjoert@ifi.uio.no> wrote:

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below):
"PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.

The (roughly) equivalent code in a Ruby extension would be:

   $result = rb_ary_new2(size);
   for (int i = 0; i < size; i++)
       rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

Hope this helps,

Lyle

As an alternative to rb_ary_store(), you can access the buffer underlying
the Array directly:

    $result = rb_ary_new2(size);
    for (int i = 0; i < size; ++i)
      RARRAY($result)->ptr[i] = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.

···

In article <d4cf71b0050127093664c9bf7b@mail.gmail.com>, Lyle Johnson wrote:

On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen ><asbjoert@ifi.uio.no> wrote:

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below):
"PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.

The (roughly) equivalent code in a Ruby extension would be:

   $result = rb_ary_new2(size);
   for (int i = 0; i < size; i++)
       rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

Tim Sutherland wrote:

In article <d4cf71b0050127093664c9bf7b@mail.gmail.com>, Lyle Johnson

wrote:

>

(...)

As an alternative to rb_ary_store(), you can access the buffer

underlying

the Array directly:

    $result = rb_ary_new2(size);
    for (int i = 0; i < size; ++i)
      RARRAY($result)->ptr[i] = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.

There is a gotcha to this though.
rb_ary_new2(size) returns an array with length==0 and capacity==size.
The example you give above never increases length.
You could fix this with
RARRAY($result)->len = size;
However, this is also a gotcha. If you put it before the loop then the
array is filled with a bunch of garabage references which will crash
Ruby if the GC is run when rb_float_new() is called. If you put it
after he loop then all those floats you create could be destroyed by
the GC, causing Ruby to crash later.
rb_ary_store() is the simplest and safest solution. You could also do:

$result = rb_ary_new2(size);
for ( ; RARRAY($result)->len < size; RARRAY($result)->len++) {
int i = RARRAY($result)->len;
RARRAY($result)->ptr[i] = rb_float_new((double) p(i+1)));
}

-Charlie

···

>On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen > ><asbjoert@ifi.uio.no> wrote:

Thank you all for the response. :slight_smile:

I think comp.lang.ruby is a great newsgroup with friendly and highly competent people. I really enjoy reading the postings of my interesst, and that`s a lot. I spend nearly an hour reading this newsgroup each day, and have allready posted at least 3 mail to it myselfe.

I am missing a site for n00bs to program extending Ruby though, does there exist any ? I have read README.EXT and I have bought the wonderful Pickaxe2.

What about "extending" the Ruby exam site (http://www.rubygarden.org/ruby?RubyExam\) with an "extending Ruby" part ?

···

On Fri, 28 Jan 2005, Charles Mills wrote:

Tim Sutherland wrote:

In article <d4cf71b0050127093664c9bf7b@mail.gmail.com>, Lyle Johnson

wrote:

On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen >>> <asbjoert@ifi.uio.no> wrote:

(...)

As an alternative to rb_ary_store(), you can access the buffer

underlying

the Array directly:

    $result = rb_ary_new2(size);
    for (int i = 0; i < size; ++i)
      RARRAY($result)->ptr[i] = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.

There is a gotcha to this though.
rb_ary_new2(size) returns an array with length==0 and capacity==size.
The example you give above never increases length.
You could fix this with
RARRAY($result)->len = size;
However, this is also a gotcha. If you put it before the loop then the
array is filled with a bunch of garabage references which will crash
Ruby if the GC is run when rb_float_new() is called. If you put it
after he loop then all those floats you create could be destroyed by
the GC, causing Ruby to crash later.
rb_ary_store() is the simplest and safest solution. You could also do:

$result = rb_ary_new2(size);
for ( ; RARRAY($result)->len < size; RARRAY($result)->len++) {
int i = RARRAY($result)->len;
RARRAY($result)->ptr[i] = rb_float_new((double) p(i+1)));
}

-Charlie