开发者

rb_iv_get and rb_iv_set VS. Data_Wrap_Struct for creating custom classes

rb_iv_get and rb_iv_set VS. Data_Wrap_Struct for custom calsses

So, reading the Ruby Exten开发者_JS百科sion API I found Data_Wrap_Struct which converts a pointer into a Ruby object (right?). However, when I tried using is I kept getting random errors and whatnot, so I kind of though of switching to something like:

void Init_custom() {
    //cCustom declared as VALUE higher in the code
    cCustom = rb_define_class("Custom", T_OBJECT);
    rb_define_method(mTester, "initialize", init_Custom, 1);
    rb_define_method(mTester, "someValue", someValue_get_Custom, 0);
    rb_define_method(mTester, "someValue=", someValue_set_Custom, 1);
    //And so on.
}

Secondly the someValue_get_Custom and someValue_set_Custom would be:

VALUE someValue_get_Custom(VALUE self) {
    return rb_iv_get(self, "@someValue")
}

VALUE someValue_set_Custom(VALUE self, VALUE val) {
    return rb_iv_set(self, "@someValue", val) //or do I have to do return val;?
}

Another option would be to create a C version of attr_accessor which would make the code slightly shorter and DRYer, but it would still be a part of plan B (using rb_iv_ set/get).


Now, I would really love to figure out how to use Data_Wrap_Struct, since I have a suspicion it might be faster than using rb_iv_set and rb_iv_get, but if it's not what I think it is, then I'll have to resort to plan B.

So, I guess the real question is:

What exactly does Data_Wrap_Struct do and how to properly use it or just use it without erroring.


Oh, and I almost forgot, a few more questions related to Data_Wrap_Struct:

What exactly does the mark parameter (a function) do? It says to set the mark parameter to 0 if the object isn't referenced anywhere, but what if it is referenced somewhere (a RArray maybe)?

Secondly, would the free parameter (also a function) be a simple function that frees the allocated memory for that object?

And is anything passed to those two functions by the Garbage Collector, maybe a VALUE self?

Thanks!


Those are a lot of questions, I'll try to answer those that I can answer in a few sentences.

Think of Data_Wrap_Struct as a thin Ruby wrapper that is visible in Ruby as a "normal" object, but actually carries a reference to a C struct (could be anything in theory but just makes sense really for complex types) under its hood. The idea is that this way you can attach a struct to a Ruby object and at any time have access to the struct data whenever Ruby requests it by sending messages to that wrapper object. In C you then retrieve the data from the struct, transform it into something rubyish and pass it back. Or you do the opposite when you are requested to set data in the wrapper object - you transform Ruby data into data that is appropriate for the struct.

When the garbage collector decides to collect the wrapper object it also wants to free the underlying C struct - this is the job of the free argument, it's a function pointer to a function that takes the struct type as an argument and ought to free that struct's memory.

The mark parameter is a lot more complicated, I'd advise you to post this as a separate question. The good thing: most of the time you won't need it.

rb_iv_get, rb_iv_set, as well as rb_ivar_get and rb_ivar_set are for a totally different purpose. They set instance variables of your Ruby object and my guess is this was what you actually were looking for. The point here is that you get/set VALUEs here, i.e. you are working with Ruby objects here instead of plain C types.

You don't have to write your C version of attr_accessor, it's already there: rb_attr.

To sum this up: Data_Wrap_Struct wraps a container object over your C struct but other than that provides no functionality yet. You should use rb_attr in your Init method if you intend to have attr_accessor functionality. Use rb_iv* if you actually want to set or get instance variables explicitly.`


I agree that there is a lack of a definite resource on how to write C extensions for Ruby. There are a lot of blog posts, though. From my own experience, I would probably start with the Pickaxe PDF that Serabe mentioned in the comments and there is an actually pretty neat introduction in the Ruby sources (README.EXT). After that the best thing you can do is to look into the extensions in the ext directory in the Ruby sources. Pick one you're familiar with or whose functionality you like and play with it. Always have the Ruby source code at hand. If you don't know what a particular function does, look its declaration up in the sources to get at least a feeling for what it does. You don't need to understand it all at first glance, but it generally gives you enough to move on with your task.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜