C++ Modules

Extending Ry with native speed.

Extending Ry with C++

One of Ry's most powerful features is its ability to load and interact with native C++ code. This allows you to write performance-critical code in C++, access system-level APIs, or integrate with existing C++ libraries.

Creating a Native Module

A native module is a C++ source file that defines one or more functions to be exposed to Ry. You'll need to include the Ry C++ header and define an initialization function.

Let's create a simple math library called mymath.cpp.

// mymath.cpp
// Note: This requires a C++ compiler and the Ry Library Development Kit (libry_dk.h)
#include "libry_dk.h" // The Ry Library Development Kit header.

// Native functions receive the arg count and a pointer to the args.
RyValue native_add(int argCount, RyValue* args, std::map<std::string, RyValue &globals) {
    // Expect two number arguments.
    if argCount != 2 || !args[0].is_number() || ! {
        return RyValue(); // Returns null.
        // For the module to see an error message I highly recommend to write a .ry file with a panic keyword
    }
    double a = AS_NUMBER(args[0]);
    double b = AS_NUMBER(args[1]);
    return NUMBER_VAL(a + b);
}

// The VM looks for a function named `init_ry_module` to initialize the module.
extern "C" void ry_init_module(RyRegisterFn reg, void *target) {
    reg("add", native_add);
}

Compiling the Module

The C++ code must be compiled into a shared library (.so on Linux, .dylib on macOS, .dll on Windows) that the Ry interpreter can load at runtime.

# Compile on Linux/macOS
g++ -shared -fPIC -o mymath.so -O3 -march=native -flto -DNDEBUG -std=c++20 mymath.cpp

Using the Module in Ry

Use the built-in use() function to load your compiled module. Ry automatically searches for the library in standard paths and the current script's directory. Once loaded, the native functions are available globally.

# main.ry
# Loads mymath.so and executes its init function.
use("mymath")
data result = add(15, 27)
out("The native result is: ${result}") # Output: The native result is: 42

Error Handling

Returning nil is a simple way to signal failure, but it doesn't provide any message. For a more beautiful error handling, you can use the VM's panic system.

Let's dive even deeper into how Ry works by examining its Bytecode.

Next: Bytecode!