Skip to content

Overview

Rice is a header-only C++ library that bridges Ruby and C++ using template metaprogramming. This section explains the key architectural concepts that make Rice work.

Core Design Principles

Header-Only Rice requires no compilation—just include the headers. All implementation is in .hpp and .ipp files.

Template Metaprogramming Rice uses C++ templates to automatically deduce types at compile time, eliminating boilerplate code.

Type Safety The C++ type system catches errors at compile time rather than runtime.

Minimal Ruby C API Exposure Rice wraps Ruby's C API (VALUE, rb_* functions) so users rarely interact with it directly.

Call Flow

The diagram below shows how Rice's components interact when a Ruby method calls into C++:

Ruby Code
    |
    v
+------------------+
|   Ruby VM        |  Calls registered RUBY_METHOD_FUNC
+--------+---------+
         |
         v
+------------------+
| Native::resolve  |  Finds matching overload from NativeRegistry
+--------+---------+
         |
         v
+------------------+
|   From_Ruby<T>   |  Converts Ruby VALUEs to C++ types
+--------+---------+
         |
         v
+------------------+
|   C++ Method     |  Your actual C++ code executes
+--------+---------+
         |
         v
+------------------+
|   To_Ruby<T>     |  Converts C++ return value to Ruby VALUE
+--------+---------+
         |
         v
Ruby Code (receives result)

Key Components

Rice is organized into several subsystems:

Type Binding Data_Type<T> and Wrapper<T> - Binding C++ types to Ruby classes and managing object storage.

Method Binding Native hierarchy - Binding C++ functions and methods to Ruby.

Overload Resolution How Rice selects the correct C++ overload based on Ruby arguments using precision-based scoring.

Types Overview From_Ruby<T> and To_Ruby<T> - Converting values between languages.

Registries Runtime tracking of types, methods, and instances.

Enumerators Implementing Ruby-style iteration for C++ containers.

Thread Safety

Rice itself is thread-safe for reading (method invocation). However:

  • Type registration (define_class, define_method) should happen during extension initialization
  • Ruby's Global VM Lock (GVL) applies to all Ruby-touching code
  • Use NoGVL to release the GVL for long-running C++ operations (see GVL)