Problem with rb_block_given_p() calling context?

B

Berger, Daniel

Hi all,

Ruby 1.8.2
Solaris 9

I'm having problem with rb_block_given_p() in a C extension. It seems
to be evaluated by a constructor when it shouldn't be. Here's the C
code:

/* fab.c */
#include "ruby.h"

VALUE cFoo, cFab;

static VALUE foo_init(VALUE self){
if(rb_block_given_p())
rb_yield(self);

return self;
}

static VALUE fab_get_foos(VALUE klass, VALUE rbNum){
VALUE argv, rbFoo;
int i = 0;
int n = NUM2INT(rbNum);

for(i = 0; i < n; i++){
rbFoo = rb_class_new_instance(0,&argv,cFoo);
rb_iv_set(rbFoo,"@some_arg",INT2FIX(i));

if(rb_block_given_p()){
rb_yield(rbFoo);
}
}
return Qnil;
}

void Init_fab(){
cFab = rb_define_class("Fab",rb_cObject);
cFoo = rb_define_class("Foo",rb_cObject);

rb_define_method(cFoo, "initialize", foo_init, 0);
rb_define_attr(cFoo,"some_arg", 1, 1);

rb_define_singleton_method(cFab, "get_foos", fab_get_foos, 1);
}

Now, if I run a sample script, I get this as the result:

# test1.rb
require "fab"
Fab.get_foos(3){ |f| p f.some_arg }

# result
nil
0
nil
1
nil
2

Why am I getting the nil? It looks like it's evaluating the call to
rb_block_given_p() on the Foo constructor, i.e. in foo_init, even though
I'm not explicitly passing it there.

A pure Ruby version doesn't seem to have this problem:

# test2.rb
class Foo
attr_accessor :some_arg
def initialize
yield self if block_given?
end
end

class Fab
def self.get_foos(num)
0.upto(num){ |i|
f = Foo.new
f.some_arg = i
yield f if block_given?
}
end
end

if $0 == __FILE__
Fab.get_foos(5){ |f|
p f.some_arg
}
end

# result
0
1
2

What have I done wrong?

Regards,

Dan
 
G

George Ogata

Berger said:
Why am I getting the nil? It looks like it's evaluating the call to
rb_block_given_p() on the Foo constructor, i.e. in foo_init, even though
I'm not explicitly passing it there.

Calling a C function like `rb_class_new_instance' doesn't equate to a
method call. The latter involves pushing on the ruby stack, the
former doesn't. Same thing would happen if you called rb_ary_each in
a similar situation -- the block would be "propagated" when you may
not want it to be. Using `rb_funcall' to call Foo#new will work; I
don't know if there's a better way.
 
G

George Ogata

Berger said:
Why am I getting the nil? It looks like it's evaluating the call to
rb_block_given_p() on the Foo constructor, i.e. in foo_init, even though
I'm not explicitly passing it there.

Calling a C function like `rb_class_new_instance' doesn't equate to a
method call. The latter involves pushing on the ruby stack, the
former doesn't. Same thing would happen if you called rb_ary_each in
a similar situation -- the block would be "propagated" when you may
not want it to be. Using `rb_funcall' to call Foo#new will work; I
don't know if there's a better way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top