On Thu, Dec 27, 2007 at 08:07:31AM +0900, Jason Roelofs wrote:
>    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

Your code doesn't use dynamically-generated function pointers; it uses
function objects.  If you want dynamically-generated function pointers
(which you probably don't), you'll need to use something like ffcall or
similar.

Ruby can't call function objects directly; it can only call function
pointers.  Unfortunately, the Ruby API doesn't provide a mechanism to
attach data to a particular method, which is necessary in order to
provide call a function object from inside a function.

The Rice library uses function objects to automatically do type
conversion from Ruby type to C++ type (and back again when the function
returns).  It gets around the above limitation by mapping class name and
method name to the data, then doing a lookup (*) when the function is
called to get a pointer to a base class.  The conversion function is
then just a virtual function call on the retrieved pointer.

Take a look at rice/detail/method_data.cpp if you want the gory details.

>    possible, I guess I could go with method_missing, and dispatch the
>    call in C++ according to the name, but man, that sounds hacky.

Using method_missing would be hacky.  Fortunately, on Ruby 1.8, you can
get the name of the function just called via ruby_frame->last_class and
ruby_frame->last_func.  Ruby 1.9 gives an interface to get the method
name via rb_frame_callee() (**).

>    typedef VALUE (ruby_method)(...);
...
>    boost::function2<VALUE, VALUE, VALUE> f1;
...
>    void Init_function_test()
>    {
>      f1 = boost::bind<VALUE>(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);

This cast is invalid.  f1 is a boost::function, not a function pointer.
You need to create a wrapper function as mentioned above.

Incidentally, at one point I attempted to add support for function
objects to Rice, but I gave up when I realized that I couldn't make it
work with boost::bind (since operator() in the object returned by
boost::bind is a template function, which makes introspection on the
parameter types and return type impossible).  I might give this another
shot sometime, but it's unfortunately non-trivial.

>    }

Paul


(*) To avoid memory allocation, the actual data is stored in the unused
member of the CFUNC node that Ruby allocates when the method is defined.

(**) AFAICT, there's no function interface to get the class that was
just called.  I'll likely cross this bridge when I port Rice to 1.9.