Ben Thomas wrote:

> There is a lot of function in the Ruby C API that takes the
> 
>     VALUE (*body)(), VALUE args
> 
> combo parameters (such as rb_protect, or rb_rescue), and I don't 
> understand how I should pass multiple arguments with such declaration. 
> For example, how should I rb_protect a function call like this?
> 
>     rb_const_get( rb_cObject, rb_intern( "Foo" ) );
> 
> I saw other source cde like this:
> 
>     VALUE args[2];
>     args[0] = rb_cObject;
>     args[1] = rb_intern( "Foo" );
> 
>     rb_protect( rb_const_get, args, &result );
> 
> But this kind of code doesn't works (and just don't make sense for me 
> after what I read from eval.c, but maybe I'm missing something).

It is *very* non-obvious (at first glance) how functions like 
rb_rescue() and rb_protect() work.

The second argument to rb_protect() is just a pointer to "some data", 
and the contents of that data are up to you. That data pointer will be 
passed as the single argument to the function you pass as the first 
argument to rb_protect(), so when you write:

     rb_protect(func, data, &result);

you should understand that Ruby will execute the line:

     func(data);

For the example you described, it's not working because the function 
rb_const_get() is expecting two arguments, not one. So what to do?

This usually means you'll need to provide a "helper" function for the 
function you're actually trying to "protect". Still using your example 
scenario, let's cook up a helper for rb_const_get() that takes just one 
argument:

     VALUE rb_const_get_helper(VALUE data)
     {
         VALUE *args = (VALUE *) data;
         return rb_const_get(args[0], args[1]);
     }


Here, we're assuming that 'data' points to a C array of VALUEs, and that 
array has two elements. This function just turns around and calls the 
real function, rb_const_get(), with the correct number of arguments. To 
activate this with rb_protect(), we can now use the original snippet you 
posted:

     VALUE args[2];
     VALUE result;
     int state;

     args[0] = rb_cObject;
     args[1] = rb_intern("Foo");

     result = rb_protect(rb_const_get_wrapper, (VALUE) &args[0], &state);

Hope this helps,

Lyle