Submitted by Paul Brannan (Tue Jan 27 14:01:48 UTC 2004)
When defining methods from C, sometimes it is useful to have a single C function implement multiple Ruby methods. In order to have a single function implement multiple methods (and have slightly different behavior in each case), it is necessary to be able to attach data to the method. The usefulness of this becomes very apparent in C++ when template tricks are used to define Ruby methods.
It is possible in Ruby 1.6 to attach arbitrary data to a method using Module#define_method() and rb_iterate(). Note that this is an order of magnitide slower than a normal method.
It is possible in Ruby 1.8 to attach arbitrary data to a method like so:
struct Data {
int value; }; VALUE foo(VALUE self) { struct Data * data = (struct Data *)(ruby_current_node->nd_entry); printf("%d\n", data->value); } NODE * node = NEW_CFUNC(foo, 0); node->nd_entry = (global_entry *)data; rb_add_method(rb_cFoo, rb_intern("foo"), node, NOEX_PUBLIC);</pre>
However, this code:
<li>Assumes that the third element in the node is not used for anything (if it ever is, then this code will break). <li>Does not allow Ruby objects to be stored as data (they won't be properly marked when the GC starts).
VALUE that can be returned to the user when his function is called. By default this value will be nil.
node is marked.
void rb_add_data_to_function(VALUE klass, ID id, VALUE data); This function will look up the node for the given method and add data to the nd_value field for that method's node, if the method is a CFUNC, otherwise an exception should be raised.
last cfunc called from the interpreter: VALUE rb_get_function_data();
The above code can now be rewritten as:
struct Data {
int value; }; VALUE foo(VALUE self) { struct Data * data; Data_Get_Struct(rb_get_function_data(), rb_cObject, data); printf("%d\n", data->value); } rb_define_method(rb_cFoo, "foo", foo, 0); VALUE v = Data_Wrap_Struct(rb_cObject, 0, 0, data); rb_add_data_to_function(rb_cFoo, "foo", v);</pre>
Comments | Current voting | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
I understand your demand, so that I will not reject this RCR. But this feature should be implemented by the different API, so that it can be reentrant. Attached data should be retrieved via some kind of struct that holds calling information.
--matz.
I'm not sure I understand why this solution isn't re-entrant. Can you elaborate?
I do like the idea of retrieving calling information via a struct. Such a struct could hold the name of the function that was called (if available) and the object it was called on, in addition to whatever Ruby object was attached to the function.
-- Paul Brannan