From: Jason Roelofs Date: 2007-12-27T08:07:31+09:00 Subject: Re: C++ Functors and Ruby extensions ------=_Part_12789_25082691.1198710433732 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Dec 25, 2007 9:44 PM, gga wrote: > On Dec 24, 4:02 pm, Jason Roelofs wrote: > > I'm using Boost right now, and have tried > > Boost.Function and Boost.Bind to no avail (the code compiles but the > actual > > call causes a seg fault, I assume the memory location is voided after > the > > init is done, so trying to pass execution to a bad memory location, but > I'm > > not sure). For the record, I am trying my hand at a Boost.Ruby library. > > > > Your assumption is correct. You can't do it. The functor needs to > remain visible in memory. Also, depending on your compiler, the way C+ > + functions expect arguments may be different from what ruby expects > in its C API (this is usually a problem with Windows' __stdcall vs. > __fastcall, etc). > You will also not get ANY speed benefit from using a functor, thou, so > using it is kind of pointless. > > > > I'm also wondering if there is another way to add methods to Kernel or > > Classes outside of the rb_define_* methods. In Python you can do > > PyObject_SetAttr(namespace, name, PyCFunction) which is effectively (" > > namespace.name = function"). I've yet to find an equivalent in Ruby. > > No. > > class A > def f; end > end > > repeat as many times as needed. Classes are open in ruby. > rb_define_* do just the above and is equivalent to python's adding of > functions. > > Overall, as the other poster said, you should use SWIG. There's > really no benefit to using a C++ approach to wrapping code like > Boost.Python does. If anything, Boost.Python is much more primitive > than what swig can do. > > SWIG does not handle nested classes, a *serious* defect to what I'm trying to do. I've looked into helping add this feature, but the amount of work required makes it more feasible to build a better, Ruby-specific wrapper system. And comparing Boost.Python to SWIG really doesn't make sense. You need to compare Boost.Python with Py++ to SWIG. I'm going to post this to Ruby-core as well to see if I can glean any insight from those who know the innards of Ruby. For Ruby-core: Is the following code bit even possible or feasible, to the best of your knowledge. Basically, I need to send a dynamically generated function pointer to rb_define_* methods. If this is not possible, I guess I could go with method_missing, and dispatch the call in C++ according to the name, but man, that sounds hacky. Anyway, here is the proto code I'm using to figure this out: function_test.cpp: #include "ruby.h" #include #include #include using namespace std; typedef VALUE (ruby_method)(...); struct ruby_func { VALUE operator()(VALUE self, VALUE args) { cout << "In functor" << endl; //cout << "Function called, name " << m_name << endl; return Qnil; } }; ruby_func func; boost::function2 f1; VALUE func_check(VALUE self, VALUE args) { if (f1) { cout << "Function object exists" << endl; // And just to prove, call it f1(Qnil, Qnil); } else { cout << "Function object does not exist" << endl; } return Qnil; } extern "C" void Init_function_test() { f1 = boost::bind(func, _1, _2); // Prove that boost::bind worked correctly f1(Qnil, Qnil); // Method created to check that the function object still exists in memory rb_define_global_function("check_function", (ruby_method*) &func_check, -2); // Actual function call, this causes segfault rb_define_global_function("do_function_test", (ruby_method*) &f1, -2); } test.rb: require 'function_test' # Proper output from extension check_function # Segfault do_function_test Thanks for your help. Jason ------=_Part_12789_25082691.1198710433732--