RCR 202: Attach arbitrary data to methods defined in extensions
  submitted by Paul Brannan on Tue Jan 27 2004 09:52:48 AM -0800
  Status: pending
  
  Abstract
  
    It would be useful to be able to attach data to a method from C so that when that method gets called, it is possible to retrieve the data associated with the method. This involves adding two new functions, rb_add_data_to_function() and rb_get_function_data().
  
  Problem
  
    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);
    However, this code:
    
      - Assumes that the third element in the node is not used for anything (if it ever is, then this code will break).
- Does not allow Ruby objects to be stored as data (they won't be properly marked when the GC starts).
 
  Proposal
  
    The following changes should be made:
    
      - The NEW_CFUNC macro should be changed to accept a third argument which is a VALUE that can be returned to the user when his function is called. By default this value will be nil.
- The garbage collector should be changed to mark this object when a CFUNC node is marked.
- There should be an additional function to add arbitrary data to a cfunc: 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.
- There should be an additional function to retrieve the data attached to the 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);
  Analysis
  
    This solution allows data to be attached to a method (cfunc). The atached data stays with the method even if the method's name is changed, since it is attached to the node defining the method.
  
  
  
  Back to RCRchive.
  
  RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog