Is It Possible to Create Block from within C?

Hi,

I have the following Ruby code:

obj.func() do |arg|
    statements
end

How can I translate this into the corresponding C code? Basically the
function func() takes a block and it has been written in C without any
problem and it already works with Ruby scripts. Is it simply
impossible to create a Ruby block from within C, just as it is impossible
to get function pointers of the Ruby methods (as they are stored as
nodes)?

Regards,

Bill

Hi,

I have the following Ruby code:

obj.func() do |arg|
    statements
end

How can I translate this into the corresponding C code? Basically the
function func() takes a block and it has been written in C without any
problem and it already works with Ruby scripts. Is it simply
impossible to create a Ruby block from within C, just as it is impossible
to get function pointers of the Ruby methods (as they are stored as
nodes)?

To call a method with block:

static VALUE
statements(VALUE arg, VALUE val)
{
    return block_result;
}

static VALUE
call_func(VALUE obj)
{
    return rb_funcall(obj, rb_intern("func"), 0);
}

rb_iterate(call_func, obj, statement, 0);
···

At Thu, 5 Sep 2002 03:24:57 +0900, William Djaja Tjokroaminata wrote:


Nobu Nakada

Thanks for the help. So again and again, the key is apparently
“rb_iterate()”. Am I correct if I assume that we cannot create a
“physical” Ruby block in C (something which is of class Proc, which can
be “call”-ed)?

(Yesterday when I browsed the Ruby classes, there is no such thing as
“proc.c”, even though Proc is one of the built-in classes. So I assume
that Proc and Ruby block are “special”, which belong only to the Ruby
parser/interpreter, but not accessible via the C API’s. Now I see where
Joel VanderWerf was going when he answered how to convert a Proc into a
block in C.)

Regards,

Bill

···

============================================================================
nobu.nokada@softhome.net wrote:

obj.func() do |arg|
    statements
end

To call a method with block:

static VALUE
statements(VALUE arg, VALUE val)
{
    return block_result;
}
static VALUE
call_func(VALUE obj)
{
    return rb_funcall(obj, rb_intern("func"), 0);
}
rb_iterate(call_func, obj, statement, 0);


Nobu Nakada

Hi,

Using “rb_iterate()”, it works! Now, my code looks like

nextState = nil
trans.each_key do |key|
    if trans[key] == true
        if nextState.nil? then nextState = key
        else raise_exc ("multiple transitions defined") end
    end
end
if nextState.nil?
    ....

There are several problems here. First, inside the block I need to get
the value of both “trans” and “nextState”. No big deal, I just pack them
into a rb_ary in the last argument of rb_iterate(). Second, I need to get
the value of “nextState” after rb_iterate() finishes. Probably I can wrap
the pointer of nextState in a BigNum, but it will look too ugly. The
“best” solution so far is to do array manipulation to get the value of
nextState back.

Is there an easier or standard way of accessing the “logically enclosing
local” variable in a “logical Ruby block” in C, such as for the
“nextState” variable in the code above?

Regards,

Bill

···

=============================================================================
nobu.nokada@softhome.net wrote:

To call a method with block:

static VALUE
statements(VALUE arg, VALUE val)
{
    return block_result;
}
static VALUE
call_func(VALUE obj)
{
    return rb_funcall(obj, rb_intern("func"), 0);
}
rb_iterate(call_func, obj, statement, 0);

Hi,

Thanks for the help. So again and again, the key is apparently
“rb_iterate()”. Am I correct if I assume that we cannot create a
“physical” Ruby block in C (something which is of class Proc, which can
be “call”-ed)?

In 1.7, you can use rb_proc_new(), however, in 1.6 you need to

  1. create temporary object,
  2. define singleton method of the object with the function,
  3. get the Method object, and
  4. convert it to Proc.

See nodeDump for detail.

(Yesterday when I browsed the Ruby classes, there is no such thing as
“proc.c”, even though Proc is one of the built-in classes. So I assume
that Proc and Ruby block are “special”, which belong only to the Ruby
parser/interpreter, but not accessible via the C API’s. Now I see where
Joel VanderWerf was going when he answered how to convert a Proc into a
block in C.)

It’s defined in eval.c. Well, you can call it “special” in the
sense that it needs to access interpreter internals.

Is there an easier or standard way of accessing the “logically enclosing
local” variable in a “logical Ruby block” in C, such as for the
“nextState” variable in the code above?

Pass struct address casting to VALUE.

untested code.

struct arg {
    VALUE trans, nextState;
};

static VALUE
statements(VALUE key, struct arg *arg)
{
    if (rb_funcall(arg->trans, rb_intern("[]"), 1, key) == Qtrue) {
        if (NIL_P(arg->nextState))
            arg->nextState = key;
        else
            rb_raise(rb_eRuntimeError, "multiple transitions defined");
    }
    return Qnil;
}

static VALUE
call_func(VALUE obj)
{
    return rb_funcall(obj, rb_intern("each_key"), 0);
}

struct arg arg;
arg.trans = trans;
arg.nextState = Qnil;
rb_iterate(call_func, trans, statement, (VALUE)&arg);
···

At Thu, 5 Sep 2002 22:47:41 +0900, William Djaja Tjokroaminata wrote:
At Fri, 6 Sep 2002 00:27:57 +0900, William Djaja Tjokroaminata wrote:


Nobu Nakada

Hi,

Thanks a lot for all the information. So it seems that probably it is an
“acceptable” or “common” practice in the Ruby-C world to cast an address
to a VALUE. (I do hope that Ruby will always have the size of VALUE to be
identical to the size of pointer in all its future versions.)

Regards,

Bill

···

============================================================================
nobu.nokada@softhome.net wrote:

Pass struct address casting to VALUE.

untested code.

struct arg {
    VALUE trans, nextState;
};

(…deleted…)

struct arg arg;
arg.trans = trans;
arg.nextState = Qnil;
rb_iterate(call_func, trans, statement, (VALUE)&arg);


Nobu Nakada