Creating a reference to a ruby variable in a C extension

Hi!

I’m just making my first C extension and have a question about creating
a reference to a ruby variable, that’s passed as a method parameter to
my C
equivalent of initialize. I need this variable to be available after the
method has exited because I wan’t to call methods on the class
represented by that variable.

This is what I’ve done so far after reading the README.EXT etc,

static VALUE ref;

/* The initialize method. */
static VALUE init(VALUE self, VALUE arg)
{

ref = arg;
rb_global_variable(&ref);
}

Then later on I wan’t to use it like this:

void call(void)
{
rb_funcall(ref, rb_intern(“some_method”), 0, 0);
}

Is this the right way to do it or should I solve the problem in another
way?

Greatful for a fast reply!

Thanx
Christer

Hello !

Then later on I wan’t to use it like this:

void call(void)
{
rb_funcall(ref, rb_intern(“some_method”), 0, 0);
}

How comes this function has no parameters ? Is it being called from
ruby, or only from C code ?

I tend to think that using global variables is not a really good idea.
We need a bit more context about what you want to do. Is it a class ?
Will it have several instances ?

In the latter case, have a look at rb_iv_get and rb_iv_set to get/set
instance variables of a class instance, something like

rb_iv_set(self, rb_intern("@variable"), arg); /* in init(…) */

and

rb_funcall(rb_iv_get(self,rb_intern("@variable")),rb_intern(“some_method”),
0, 0); /* in call */

Don’t forget as well that every single C function that can be called
directly from ruby should probably have at least one VALUE parameter and
must return a VALUE.

Cheers !

Vince

Vincent F. wrote:

Hello !

Then later on I wan’t to use it like this:

void call(void)
{
rb_funcall(ref, rb_intern(“some_method”), 0, 0);
}

How comes this function has no parameters ? Is it being called from
ruby, or only from C code ?

Thank you for the reply, I’ll try to clear things up a bit and explain
what I want to do.

The function is just an example for the sake of making my question a bit
clearer. The real functions I am using has parameters. Those functions
such as the one above will only be called from C code.

I tend to think that using global variables is not a really good idea.
We need a bit more context about what you want to do. Is it a class ?
Will it have several instances ?

In the latter case, have a look at rb_iv_get and rb_iv_set to get/set
instance variables of a class instance, something like

rb_iv_set(self, rb_intern("@variable"), arg); /* in init(…) */

and

rb_funcall(rb_iv_get(self,rb_intern("@variable")),rb_intern(“some_method”),
0, 0); /* in call */

Yes, I’m writing a tiny Ruby class in C that wraps and uses a bison/flex
generated parser. The saved variable reference will be used for making
calls on the ruby instance. When those calls are made self is long gone
out of scope sice it’s the parser who triggers the method call. The C
Ruby class just acts as a proxy or adapter between the parser and the
Ruby object.

Don’t forget as well that every single C function that can be called
directly from ruby should probably have at least one VALUE parameter and
must return a VALUE.

Cheers !

Vince

As mentioned above, it’s not invoked from Ruby.

Thanx again, Christer.

On 9/21/06, Christer S. [email protected] wrote:

How comes this function has no parameters ? Is it being called from

Ruby object.
Hi Christer,

Instead of saving it as a global variable, you could save it as a
class variable. See rb_cvar_[gs]et (defined in variable.c). Just an
idea.

Cheers,
Dave

David B. wrote:

generated parser. The saved variable reference will be used for making

Cheers,
Dave

Hi Dave!

That would work if the passed in object should be shared among all
instances of my class, but that’s not the case since it’s a callback
object that’s supplied for a particular instance of my class.

Correct me if I’m wrong but the variable is only global in my C code
since I haven’t made it visible to the Ruby environment with a
rb_gv_set(const char *name, VALUE value)?

Thanx
Christer

David B. wrote:

rb_funcall(ref, rb_intern(“some_method”), 0, 0);
The function is just an example for the sake of making my question

gone

Cheers,
since I haven’t made it visible to the Ruby environment with a
rb_global_variable is really just an alias for rb_gc_register_address.
If you later want to let the object to be garbage collected you just
need to call rb_gc_unregister_address(&value). I wish I knew about
this a couple of months ago.

Anyway, now that I know this I think the way you are going about
solving the problem is the correct one.

Thanks,
Dave

Alright…

Didn’t know about that method (rb_gc_unregister_address(&value);),
thanks Dave!

Christer

On 9/21/06, Christer S. [email protected] wrote:

}
such as the one above will only be called from C code.
rb_iv_set(self, rb_intern(“@variable”), arg); /* in init(…) */
Yes, I’m writing a tiny Ruby class in C that wraps and uses a bison/flex
idea.

Correct me if I’m wrong but the variable is only global in my C code
since I haven’t made it visible to the Ruby environment with a
rb_gv_set(const char *name, VALUE value)?

Thanx
Christer

Hi Christer,

Right you are. I can’t believe I haven’t looked at this method before.
rb_global_variable simply registers the object so that it won’t be
garbage collected. Incidentally for those interested,
rb_global_variable is really just an alias for rb_gc_register_address.
If you later want to let the object to be garbage collected you just
need to call rb_gc_unregister_address(&value). I wish I knew about
this a couple of months ago.

Anyway, now that I know this I think the way you are going about
solving the problem is the correct one.

Thanks,
Dave

[I posted that yesterday lunch time, and it didn’t get on the archive yet, so I’m posting that again.]

Hello !

That would work if the passed in object should be shared among all
instances of my class, but that’s not the case since it’s a
callback object that’s supplied for a particular instance of my class.
Correct me if I’m wrong but the variable is only global in my C
code since I haven’t made it visible to the Ruby environment with a
rb_gv_set(const char *name, VALUE value)?

Ooops… Unless I completely didn’t get you right, you’re going right
into troubles. There will always be one instance of your C variable. So
if you have several instances of your class, then everytime you use one,
you will actually use the reference that you stored in the last instance
created… it will all go wrong. I just can’t understand why your ‘self’
will be gone out of scope. Do you destroy quickly the instances of your
class ? But then, how do you expect to have a per-instance storage if
you destroy the instances ?

Cheers !

Vince

Hello !

The issue with self not being available was that I was calling yyparse()
and hadn’t configured bison so that yyparse was given any parameters,
hence self wasn’t available in the parser code. I didn’t destroy it just
couldn’t reach it. Now I have taken a different aproach. yyparse is
called with a parameter and instead of passing the callback instance as
a parameter to initialize I have made it a class/module method instead,
since the only task for my extension is to delegate the parsing routine.

Yes, bison and flex always give great fun. Just out of curiosity, what
are you parsing ?

Thanks again, though, for opening my eyes. There’s been a long time
since I wrote some C code and I didn’t think about this.

I did bump into this not so long ago… I’d rather you didn’t :wink: !

Vince

Quoting Vincent F. [email protected]:

rb_gv_set(const char *name, VALUE value)?
Cheers !

Vince

Hi Vince!

Of course, you are totally right!

The issue with self not being available was that I was calling
yyparse() and hadn’t configured bison so that yyparse was given any
parameters, hence self wasn’t available in the parser code. I didn’t
destroy it just couldn’t reach it. Now I have taken a different
aproach. yyparse is called with a parameter and instead of passing the
callback instance as a parameter to initialize I have made it a
class/module method instead, since the only task for my extension is
to delegate the parsing routine.

Thanks again, though, for opening my eyes. There’s been a long time
since I wrote some C code and I didn’t think about this.

/Christer

On 9/23/06, Christer S. [email protected] wrote:

Hi again, Vince!
Actually, this idea came to my mind when thinking about doing a Ruby
Markdown to PDF conversion utility. Then I thought that one should be
able to customize the fonts, colors etc, and since Markdown converts to
XHTML and CSS can be used to style that… Well, you get the point.

Cheers,
Christer

Hey Christer,

This sounds like an interesting project. Is it going to be open
source? I could definitely use something like this.

cheers,
Dave

Vincent F. wrote:

Hello !

The issue with self not being available was that I was calling yyparse()
and hadn’t configured bison so that yyparse was given any parameters,
hence self wasn’t available in the parser code. I didn’t destroy it just
couldn’t reach it. Now I have taken a different aproach. yyparse is
called with a parameter and instead of passing the callback instance as
a parameter to initialize I have made it a class/module method instead,
since the only task for my extension is to delegate the parsing routine.

Yes, bison and flex always give great fun. Just out of curiosity, what
are you parsing ?

Thanks again, though, for opening my eyes. There’s been a long time
since I wrote some C code and I didn’t think about this.

I did bump into this not so long ago… I’d rather you didn’t :wink: !

Vince

Hi again, Vince!

Maybe I’m well deep over my head here, but my goal is to
modify/customize the CSS parser/lexer used by KDE and Apple (in Safari)
and wrap it up as a Ruby extension. My first thing on the TODO list is
making an implementation of the SAC API, and then move on to make a DOM
implementation built upon the SAC API. My extension is calling back to a
document handler SAC implementation which I will make as a module to be
able to override only the methods interesting if one might want to make
a customized handling or implementation.

Actually, this idea came to my mind when thinking about doing a Ruby
Markdown to PDF conversion utility. Then I thought that one should be
able to customize the fonts, colors etc, and since Markdown converts to
XHTML and CSS can be used to style that… Well, you get the point.

Cheers,
Christer

David B. wrote:

On 9/23/06, Christer S. [email protected] wrote:

Hi again, Vince!
Actually, this idea came to my mind when thinking about doing a Ruby
Markdown to PDF conversion utility. Then I thought that one should be
able to customize the fonts, colors etc, and since Markdown converts to
XHTML and CSS can be used to style that… Well, you get the point.

Cheers,
Christer

Hey Christer,

This sounds like an interesting project. Is it going to be open
source? I could definitely use something like this.

cheers,
Dave

Hi David!

Well, whatever I may release will be open source. It all depends on how
much time I can put into it since I have a full day job etc. The CSS
part is my main concern, I think this is a missing piece in the Ruby
world. Maybe I’ll put up a project at rubyforge before it’s finished and
see if there’s someone who’s interested in helping out. I have my other
project http://rubyforge.org/projects/hessian to look out for as well,
but it’s a kind of (don’t know the english word) narrow technology and
dosen’t take to much time at the moment, so we’ll see.

Christer