# How to Create Custom Built-in Functions in Nelson Using the C++ Gateway API

> Learn to create custom built-in functions in Nelson using the C++ Gateway API. Implement C++ functions and register them to extend Nelson's capabilities.

- Repository: [The Nelson Programming Language/nelson](https://github.com/nelson-lang/nelson)
- Tags: how-to-guide
- Published: 2026-03-08

---

**You create custom built-in functions in Nelson by implementing a C++ function that follows the `CPP_BUILTIN` or `CPP_BUILTIN_WITH_EVALUATOR` prototype, registering it in a gateway table defined by the `nlsGateway` struct, and compiling the module as a shared library that Nelson discovers at runtime.**

Nelson is an open-source numerical computing environment that enables extending its core interpreter through native C++ modules. By leveraging the C++ Gateway API provided in the nelson-lang/nelson repository, developers can implement high-performance custom built-in functions that integrate seamlessly with the interpreter's overload resolution and evaluation mechanisms.

## Understanding the Gateway Architecture

Nelson extends its functionality through **modules**—shared libraries (`.so`, `.dll`, or `.dylib`) that export a gateway function. When Nelson loads a module, it calls `AddGateway`, which registers a table of function pointers with the interpreter.

### The nlsGateway Struct

The foundation of the C++ Gateway API is the `nlsGateway` struct defined in [`modules/interpreter/src/include/NelsonGateway.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/interpreter/src/include/NelsonGateway.hpp). This struct maps a Nelson function name to its C++ implementation:

```cpp
using nlsGateway = struct nlsGatewayStructType
{
    std::string functionName;                 // Name used from the Nelson prompt
    ptrBuiltin   fptr;                        // Pointer to the C++ entry point
    int          nLhs;                       // Minimum number of outputs
    int          nRhs;                       // Minimum number of inputs
    BUILTIN_PROTOTYPE builtinPrototype;      // CPP_BUILTIN, CPP_BUILTIN_WITH_EVALUATOR, etc.
    FunctionOverloadAutoMode builtinOverloadAutoMode;
};

```

Each field serves a specific purpose. The `functionName` field specifies the command users type at the Nelson prompt. The `fptr` field holds the function pointer, which must match the signature specified in `builtinPrototype`. The `nLhs` and `nRhs` fields enforce minimum input and output argument counts at the gateway level.

### Built-in Prototypes

The `BUILTIN_PROTOTYPE` enum, also defined in [`modules/interpreter/src/include/NelsonGateway.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/interpreter/src/include/NelsonGateway.hpp), defines three calling conventions:

```cpp
enum BUILTIN_PROTOTYPE {
    CPP_BUILTIN = 0,               // ArrayOfVector func(int nLhs, const ArrayOfVector& args);
    CPP_BUILTIN_WITH_EVALUATOR,    // ArrayOfVector func(Evaluator* eval, int nLhs, const ArrayOfVector& args);
    C_MEX_BUILTIN                  // Legacy MATLAB-compatible signatures
};

```

**`CPP_BUILTIN`** is the standard choice for most functions. It receives the argument vector and the requested number of outputs. **`CPP_BUILTIN_WITH_EVALUATOR`** provides additional access to the current `Evaluator*` instance, enabling programmatic calls to other built-ins and advanced interpreter interaction.

### The NLSGATEWAYFUNC Macro

Modules export their function table through the `NLSGATEWAYFUNC` macro found in [`modules/interpreter/src/include/NelsonGateway.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/interpreter/src/include/NelsonGateway.hpp). This macro generates the `AddGateway` entry point that Nelson calls during module loading:

```cpp
#define NLSGATEWAYFUNC(gateway) \
    NLSGATEWAYFUNCEXTENDED(gateway, NULL)

#define NLSGATEWAYFUNCEXTENDED(gateway, ptrInitializeFunction) \
    EXTERN_AS_C EXPORTSYMBOL int AddGateway(void* eval, const wchar_t* moduleFilename) \
    { \
        return NelsonAddGatewayWithEvaluator(eval, moduleFilename, (void*)gateway, \
            sizeof(gateway) / sizeof(nlsGateway), gatewayName.c_str(), (void*)ptrInitializeFunction); \
    }

```

In practice, each module contains a [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp) file that defines the gateway table and invokes this macro, as seen in [`modules/fftw/builtin/cpp/Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/fftw/builtin/cpp/Gateway.cpp):

```cpp
const std::wstring gatewayName = L"fftw";

static const nlsGateway gateway[] = {
    { "fft",  (ptrBuiltin)Nelson::FftwGateway::fftBuiltin,  1, 3, CPP_BUILTIN, AUTO_MODE_NONE },
    { "ifft", (ptrBuiltin)Nelson::FftwGateway::ifftBuiltin, 1, 3, CPP_BUILTIN, AUTO_MODE_NONE },
};

NLSGATEWAYFUNC(gateway)

```

## Step 1: Write the Built-in Implementation

Create a C++ source file in your module's `builtin/cpp` directory. The implementation must conform to one of the supported prototypes. Here is a minimal example implementing `mySquareBuiltin` using the **CPP_BUILTIN** signature:

```cpp
// mySquareBuiltin.cpp
#include "mySquareBuiltin.hpp"
#include "Error.hpp"
#include "InputOutputArgumentsCheckers.hpp"

using namespace Nelson;

ArrayOfVector mySquareBuiltin(int nLhs, const ArrayOfVector& argIn)
{
    // Enforce exactly one input and one output
    nargoutcheck(nLhs, 0, 1);
    nargincheck(argIn, 1, 1);

    ArrayOf X = argIn[0];
    if (!X.isNumeric()) {
        Error(ERROR_WRONG_ARGUMENT_1_TYPE);
    }

    // Perform element-wise square using Nelson's ArrayOf operators
    ArrayOf Y = X .* X;
    return {Y};
}

```

The `nargoutcheck` and `nargincheck` functions from [`InputOutputArgumentsCheckers.hpp`](https://github.com/nelson-lang/nelson/blob/main/InputOutputArgumentsCheckers.hpp) validate argument counts against the function's requirements. For a production-quality example, examine [`modules/fftw/builtin/cpp/fftBuiltin.cpp`](https://github.com/nelson-lang/nelson/blob/main/modules/fftw/builtin/cpp/fftBuiltin.cpp), which demonstrates input validation, dimension handling, and error reporting within the Nelson framework.

## Step 2: Register the Function in a Gateway

After implementing the function, you must register it in a gateway table. You have two approaches: manual editing for single functions, or automated generation for multiple functions.

### Manual Gateway Registration

Edit or create [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp) in your module's `builtin/cpp` directory. Include the header for your new function and add an entry to the `gateway` array:

```cpp
#include "NelsonGateway.hpp"
#include "mySquareBuiltin.hpp"

const std::wstring gatewayName = L"demo";

static const nlsGateway gateway[] = {
    { "mySquare", (ptrBuiltin)mySquareBuiltin, 1, 1, CPP_BUILTIN, AUTO_MODE_NONE },
};

NLSGATEWAYFUNC(gateway)

```

The array entry specifies: the command name `"mySquare"`, the function pointer cast to `ptrBuiltin`, minimum output count `1`, minimum input count `1`, the prototype `CPP_BUILTIN`, and the overload mode.

### Automated Generation with dlgenerategateway.m

For modules containing many built-ins, use the helper script `modules/dynamic_link/functions/dlgenerategateway.m`. This MATLAB-compatible function generates a complete [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp) from a descriptor table:

```matlab
builtin_table = {
    {"mySquare", 1, 1, "CPP_BUILTIN"},
    {"myCube",   1, 1, "CPP_BUILTIN"}
};

dlgenerategateway('modules/demo/builtin/cpp', 'demo', builtin_table);

```

The script automatically writes the [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp) file with correct `extern` declarations, the `nlsGateway` table, and all necessary macros including `NLSGATEWAYFUNC`, `NLSGATEWAYINFO`, and `NLSGATEWAYNAME`.

## Step 3: Build and Load the Module

Nelson modules build as standard CMake targets. Add your source files to the module's [`CMakeLists.txt`](https://github.com/nelson-lang/nelson/blob/main/CMakeLists.txt):

```cmake
add_library(demo SHARED
    builtin/cpp/mySquareBuiltin.cpp
    builtin/cpp/Gateway.cpp
)

target_link_libraries(demo PRIVATE nelson_core)

```

Compile the module using standard CMake commands:

```bash
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

```

Place the resulting shared library (`demo.dll` on Windows, `libdemo.so` on Linux) in a directory listed in `NELSON_MODULE_PATH`, or load it explicitly using Nelson's `addpath` function. Once loaded, the function is available at the prompt:

```octave
>> mySquare(4)
ans = 16

```

## Summary

- **Implement** your function using the `CPP_BUILTIN` or `CPP_BUILTIN_WITH_EVALUATOR` signature, validating inputs with `nargincheck` and `nargoutcheck`.
- **Register** the function in a gateway table defined in [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp), either manually or using the `dlgenerategateway.m` generator script.
- **Compile** the module as a shared library using CMake, linking against Nelson core libraries.
- **Load** the module by placing it in the Nelson modules directory or using `addpath`, making the function available immediately.

## Frequently Asked Questions

### What is the difference between CPP_BUILTIN and CPP_BUILTIN_WITH_EVALUATOR?

**CPP_BUILTIN** uses the signature `ArrayOfVector func(int nLhs, const ArrayOfVector& args)` and is suitable for standalone computations. **CPP_BUILTIN_WITH_EVALUATOR** adds an `Evaluator*` parameter, allowing the function to access the interpreter state, call other built-ins programmatically, or evaluate expressions within the current context. Choose the latter when your function needs deep integration with Nelson's execution engine.

### How does Nelson enforce argument count constraints?

The `nlsGateway` struct contains `nLhs` and `nRhs` fields that specify minimum argument counts. Additionally, implementations typically call `nargincheck(argIn, min, max)` and `nargoutcheck(nLhs, min, max)` from [`InputOutputArgumentsCheckers.hpp`](https://github.com/nelson-lang/nelson/blob/main/InputOutputArgumentsCheckers.hpp) to enforce exact counts at runtime. The gateway validates the minimums before the function executes, while the internal checks provide detailed error messages.

### Can I generate the Gateway.cpp file automatically?

Yes. The `dlgenerategateway.m` script located in `modules/dynamic_link/functions/dlgenerategateway.m` generates a complete, compilable [`Gateway.cpp`](https://github.com/nelson-lang/nelson/blob/main/Gateway.cpp) from a table of function specifications. This approach reduces boilerplate when creating modules with dozens of built-in functions and ensures consistent macro usage across the nelson-lang/nelson codebase.

### Where should I place the compiled shared library for Nelson to find it?

Nelson searches for modules in directories listed in the `NELSON_MODULE_PATH` environment variable or in the standard `modules` subdirectory of the Nelson installation. You can also load modules explicitly using the `addpath` function with the directory containing your `.so`, `.dll`, or `.dylib` file. The shared library must export the `AddGateway` symbol generated by the `NLSGATEWAYFUNC` macro.