Creating a reference to a ruby variable in a C extension.

C

Christer Sandberg

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
 
V

Vincent Fourmond

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
 
C

Christer Sandberg

Vincent said:
Hello !


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.
 
D

David Balmain

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.


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.

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
 
C

Christer Sandberg

David said:
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.


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.

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

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
 
D

David Balmain

David said:
Vincent Fourmond 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.

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

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

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
 
C

Christer Sandberg

David said:
David said:
Vincent Fourmond 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.

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

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

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

Alright...

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

Christer
 
V

Vincent Fourmond

[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
 
S

sillen

Quoting Vincent Fourmond said:
[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 !

=09Vince

Hi Vince!

Of course, you are totally right!

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

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

/Christer
 
V

Vincent Fourmond

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 ;-) !

Vince
 
C

Christer Sandberg

Vincent said:
Hello !


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


I did bump into this not so long ago... I'd rather you didn't ;-) !

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
 
D

David Balmain

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

Hey Christer,

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

cheers,
Dave
 
C

Christer Sandberg

David said:
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
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top