Types Overview#
The purpose of Rice is to enable native C++ code and Ruby code work together. This requires making it easy to translate types between the two languages.
There are three main use cases:
Converting, i.e copying, types between the two languages (Type conversion)
Enable Ruby to access C++ code via a Ruby wrapper (define_class, define_enum, etc)
Enable C++ to access Ruby code via a C++ wrapper (Ruby C++ API)
Type conversion works well for primitive types such as boolean and numeric types. For example, a C++ unsigned 32 bit integer is copied into a Ruby Fixnum instance (and vice versa). Conversion of primitive types is also easy to understand because its familiar to programmers. When you pass a boolean or integer into a method, you don’t expect the method is going to change it - instead it just gets a copy.
However, type conversion usually does not make sense for more complex types. You likely do not want to copy instances of simple C++ structures to Ruby, and you almost never want to copy instances of C++ classes. There are a lot of reasons for this, including:
C++ objects may contain uncopyable internal state, such as a database connection or an open file handle
C++ has complex object lifetime rules that control how objects are created, copied and destructed that do not translate to Ruby
A C++ object may use a lot of memory, such as a million element vector, that makes it untenable to copy it to Ruby.
Copying data, by definition, creates two separate versions making it impossible to share data between the two languages.
As a result, a more practical approach is to provide thin wrappers that allow Ruby to access C++ objects and C++ to access Ruby objects. Ruby wrappers are created via define_enum, define_class, etc. as described in other parts of the documentation.
Last, you may wish to manipulate Ruby objects from C++ using Rice’s object-oriented Ruby C++ API versus Ruby’s C api.