C++ Functors and Ruby extensions

I wonder if anyone has tried to do what I’m doing and if they’ve come up
with an appropriate solution.

Basic idea:

struct ruby_func_wrapper
{
VALUE operator()(VALUE self, VALUE args)
{
m_callback(args …);
}
}

extern “C”
void Init_functor_test() {
ruby_func_wrapper functor;
[ … code that sets callback of functor … ]

rb_define_global_function(“functor_test”, [something here &functor],
-2);
}

Basically, I want to use instances of the ruby_func_wrapper functor as
callback for Ruby methods. 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.

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.

I hope this is clear, though if not I can post the full code I’ve got
right
now.

Thanks

Jason

-------- Original-Nachricht --------

Datum: Tue, 25 Dec 2007 04:02:38 +0900
Von: “Jason R.” [email protected]
An: [email protected]
Betreff: C++ Functors and Ruby extensions

}

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.

I hope this is clear, though if not I can post the full code I’ve got
right
now.

Thanks

Jason

Dear Jason,

I think SWIG (http://www.swig.org/) may have a solution
for what you want to do:

http://www.goto.info.waseda.ac.jp/~fukusima/ruby/swig-examples/funcptr/index.html

Here’s some more information on how to use it in conjunction with
Ruby :

http://www.swig.org/Doc1.3/Ruby.html

Best regards,

Axel

I’m doing this because I SWIG doesn’t work for my current wrapping
project.

Also, SWIG generates static method wrappers. I’m trying to do this
dynamically (see Boost.Python: http://www.boost.org/libs/python/doc/)

Jason

On Dec 24, 4:02 pm, Jason R. [email protected] 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.

On Dec 25, 2007 9:44 PM, gga [email protected] wrote:

Classes outside of the rb_define_* methods. In Python you can do
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 <boost/function.hpp>
#include <boost/bind.hpp>

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<VALUE, VALUE, VALUE> 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

Jason R. wrote:

SWIG does not handle nested classes, a serious defect to what I’m
trying to do.

Which is partially not true. SWIG supports nested classes just fine but
you need to provide more glue code to expose the class as the swig
parser will not automatically parse them for you. The amount of code
you need to write is probably less than the equivalent of boost python.

Here’s a simple dummy example.


%module nested

%inline {

class A
{
public:
A() {}
~A() {}

 class B
 {
 public:
   B()  {}
   ~B() {}
 };

};

}

// We declare a typedef so that A__B will mean something to the compiler
%{
typedef A::B A__B;
%}

// the glue code— we copy the B definition here and call it A__B
class A__B
{
public:
A__B() {}
~A__B() {}
};

%init {
// we define a constant inside A so we can invoke A::B.new()
rb_define_const(cA.klass, “B”, cA__B.klass );
}

If the nested class is declared as protected, afaik, neither swig nor
boost python will be able to do much with it.

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.

Same thing.

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.

// Actual function call, this causes segfault

Sure. You are passing the address of the function object, not the
function. You might get what you want if you use f1.target(), which
returns a Functor* (ie. the address of the actual function or functor).

But again as I already mentioned, that may still prove not portable,
unless you modify boost::function, as the calling convention used in a
functor by default is probably not cdecl. For more info, see:
http://en.wikipedia.org/wiki/Stdcall

Your best bet is to avoid using a functor or call the functor through a
C function, like:

extern “C”
VALUE call_functor( VALUE self, VALUE args )
{
functor* f = (functor*) args[0];
return f->operator()(self, args[1]);
}

and always pass the functor (cast to VALUE) as the first argument to the
function. That’s slightly slower, but it is surely portable.


Gonzalo
Garramuñ[email protected]

AMD4400 - ASUS48N-E
GeForce7300GT
Xubuntu Gutsy

2007/12/27, Jason R. [email protected]:

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.

I’m not too familiar with Boost. So could you quickly summarize what
is it that you expect to gain from creating a Boost Ruby integration?

Kind regards

robert

Gonzalo Garramuño wrote:

Here’s a simple dummy example.

Actually, just looking at the swig internals, the typedef is unneeded
and the code can be simplified to just:

%module nested

// this is what’s in your .h file
%inline {

class A
{
public:
A() {}
~A() {}

 class B
 {
 public:
   B()  {}
   ~B() {}
 };

};

}

// We rename the nested class to something valid
%rename(“A__B”) A::B;

// the glue code— we copy the B definition here and call it A::B
class A::B
{
public:
B() {}
~B() {}
};

%init {
// we define a constant inside A so we can invoke A::B.new()
rb_define_const(cA.klass, “B”, cA__B.klass );
}


Gonzalo
Garramuñ[email protected]

AMD4400 - ASUS48N-E
GeForce7300GT
Xubuntu Gutsy

On Dec 27, 2007 7:36 AM, Robert K. [email protected]
wrote:

Kind regards

robert


use.inject do |as, often| as.you_can - without end

Boost.Python and luabind are libraries built to make it extremely easy
to
build interfaces into the target language from C++. It’s not really
about
integration with Boost, Boost just provides some very, very useful
constructs and a powerful meta-programming subsystem that makes this
library
feasible in such a strict language. Here’s what you’re able to do:

Wrap this:

class A {
public:
A();
A(int, int);

void doSomething();
int getSomethingBack();

};

Like this:

class_(“A”)
.def(initialize<int, int>())
.def(“do_something”, &A::doSomething)
.def(“get_something_back”, &A::getSomethingBack);

and in Ruby

a1 = A.new
a = A.new(1,2)

a.do_something
a.get_something_back

For those of you pushing SWIG, trust me, I’ve spent many, many hours
trying
different ways to make nested classes work in a way that won’t require
me to
re-write a full quarter of the headers that I’m trying to wrap (Ogre
rendering engine, for the record). Nested classes are not supported in
SWIG, there are hacks to make it look so, hacks that do not work all of
the
time.

Jason

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

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.

On Thu, Dec 27, 2007 at 11:46:24PM +0900, Jason R. wrote:

Like this:

class_(“A”)
.def(initialize<int, int>())
.def(“do_something”, &A::doSomething)
.def(“get_something_back”, &A::getSomethingBack);

Rice (http://rubyforge.org/projects/rice) lets you do it like this:

extern “C”
void Init_myextension()
{
define_class(“A”)
.define_constructor<Constructor
())
.define_method("do_something, &A::doSomething)
.define_method(“get_something_back”, &A::getSomethingBack);
}

I avoided the boost::python syntax so the library would feel more
familiar to people who use the C Ruby API.

I don’t yet have support for non-default constructors working, but I’d
welcome the help. :slight_smile:

Paul

On 27.12.2007 15:46, Jason R. wrote:

I’m not too familiar with Boost. So could you quickly summarize what

A();

.def(“do_something”, &A::doSomething)
.def(“get_something_back”, &A::getSomethingBack);

and in Ruby

a1 = A.new
a = A.new(1,2)

a.do_something
a.get_something_back

Thanks for taking the time to explain! I was not aware that something
like this is part of Boost.

For those of you pushing SWIG, trust me, I’ve spent many, many hours trying
different ways to make nested classes work in a way that won’t require me to
re-write a full quarter of the headers that I’m trying to wrap (Ogre
rendering engine, for the record). Nested classes are not supported in
SWIG, there are hacks to make it look so, hacks that do not work all of the
time.

Kind regards

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs