# How the Nelson Type Overload System Implements Custom Behaviors: A Complete Guide

> Discover how the Nelson type overload system maps function calls to custom M-files at runtime. Learn to implement specialized behaviors efficiently with this comprehensive guide.

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

---

**The Nelson type overload system maps function calls to specialized M-files using a runtime lookup that converts expressions like `a + b` into `@ClassName/plus.m` based on operand types.**

The nelson-lang/nelson interpreter provides a sophisticated type overload system that allows developers to define custom behaviors for operators and functions on user-defined classes. This mechanism relies on a deterministic naming convention, a runtime dispatcher, and configurable compatibility levels to resolve which implementation executes for any given call.

## Core Architecture of the Nelson Type Overload System

The implementation centers on three interconnected components that transform a generic function call into a specific method invocation.

### Naming Convention and Symbol Generation

The system generates overload symbols using the pattern `@ClassName/FunctionName`. This deterministic path construction allows the interpreter to locate the correct M-file without ambiguity.

In [`modules/overload/src/include/OverloadName.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/overload/src/include/OverloadName.hpp), the `getOverloadFunctionName` function constructs these symbols:

```cpp
std::string overloadName = "@" + typeName + "/" + functionName;   // e.g., "@complexObj/plus"

```

This naming convention applies to both named functions and operators. When you write `a + b`, the parser maps the `+` operator to the function name `plus`, then searches for `@ClassName/plus.m`.

### Runtime Dispatch Mechanism

The `callOverloadedFunction` routine in [`modules/overload/src/include/OverloadHelpers.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/overload/src/include/OverloadHelpers.hpp) serves as the central dispatcher. This function executes several critical steps:

1. Checks the `Evaluator::withOverload` flag (default `true`) and the current `OverloadLevelCompatibility` setting
2. Computes the **common type** of all arguments to determine which class directory to search
3. Builds the overload symbol using `getOverloadFunctionName`
4. Queries `FunctionsInMemory` to verify the M-file exists
5. Invokes the user-defined function or, for handle objects, calls `HandleGenericObject::invokeMethod`

The dispatcher also supports handle objects through a secondary path that invokes C++ methods directly when the overload symbol matches a handle class method.

### Module Registration

The overload subsystem registers itself through `modules/overload/loader.m`, which executes during interpreter startup. This registration ensures the evaluator recognizes the overload subsystem and initializes the necessary function tables.

## How Overload Resolution Works at Runtime

When the interpreter encounters a function call with custom types, it follows a deterministic resolution path controlled by compatibility settings.

### Compatibility Levels

Nelson provides three overload resolution modes defined in the configuration system ([`modules/nelson_manager/src/include/NelsonConfiguration.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/nelson_manager/src/include/NelsonConfiguration.hpp)):

- **`NLS_OVERLOAD_NONE`** (0): Disables all overload resolution; only built-in functions execute
- **`NLS_OVERLOAD_OBJECT_TYPES_ONLY`** (1): Resolves overloads only for user-defined class types
- **`NLS_OVERLOAD_ALL_TYPES`** (2): Enables overloads for any type, including built-in primitives

The `setOverloadLevelCompatibility` method stores the selected mode, which `callOverloadedFunction` checks via a switch statement (lines 73-94 in [`OverloadHelpers.hpp`](https://github.com/nelson-lang/nelson/blob/main/OverloadHelpers.hpp)) before attempting resolution.

### Resolution Sequence

For a call like `plus(a, b)` where `a` and `b` are custom objects:

1. The parser identifies the function name `plus` and arguments `a`, `b`
2. The evaluator checks if `withOverload` is enabled and verifies the compatibility level permits resolution for these types
3. The system determines the common type (e.g., `complexObj`)
4. `getOverloadFunctionName` constructs `@complexObj/plus`
5. The function table searches for `modules/overload/examples/complex/@complexObj/plus.m`
6. Upon finding the file, the interpreter executes the M-file with `a` and `b` as arguments

## Implementing Custom Type Overloads in Nelson

Creating custom behaviors requires organizing M-files into class directories following the `@ClassName` convention.

### Creating a Class with Operator Overloading

To implement a custom complex number class that overloads the `+` operator:

1. Create the class directory structure:

```matlab
% Save as: modules/overload/examples/complex/@complexObj/complexObj.m
function obj = complexObj(r, i)
   obj.r = r;          % real part
   obj.i = i;          % imaginary part
   obj = class(obj, 'complexObj');
end

```

2. Implement the addition operator:

```matlab
% Save as: modules/overload/examples/complex/@complexObj/plus.m
function r = plus(a, b)
   % Custom addition for complexObj instances
   R1 = a.r + b.r;
   R2 = a.i + b.i;
   r = complexObj(R1, R2);
end

```

3. Add the class to the path and test:

```matlab
addpath([nelsonroot(), '/modules/overload/examples/complex']);
a = complexObj(1, 2);
b = complexObj(3, 4);
c = a + b;      % Dispatches to @complexObj/plus.m
disp(c);

```

### Overloading Arithmetic Operators

For a custom numeric wrapper that overloads subtraction:

```matlab
% @myNumber/myNumber.m – constructor
function obj = myNumber(v)
    obj.value = v;
    obj = class(obj, 'myNumber');
end

% @myNumber/minus.m – binary subtraction overload
function r = minus(a, b)
    r = myNumber(a.value - b.value);
end

```

Usage:

```matlab
addpath('path/to/@myNumber');
x = myNumber(10);
y = myNumber(3);
z = x - y;    % Returns myNumber(7)
disp(z.value); % Output: 7

```

## Configuring Overload Behavior

Control the Nelson type overload system through the configuration API to optimize performance or ensure compatibility.

### Runtime Configuration

Adjust overload resolution without restarting the interpreter:

```matlab
% Disable overloads completely for maximum performance
NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_NONE);

% Enable overloads only for user-defined classes (safer)
NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_OBJECT_TYPES_ONLY);

% Enable full overload support (default)
NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_ALL_TYPES);

```

### Temporary Disabling Pattern

For performance-critical sections where built-in behavior is required:

```matlab
% Save current setting
prevSetting = NelsonConfiguration().getOverloadLevelCompatibility();

% Turn overloads off
NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_NONE);

% Execute performance-critical code with built-in functions only
result = computeIntensiveOperation(data);

% Restore previous setting
NelsonConfiguration().setOverloadLevelCompatibility(prevSetting);

```

The `Evaluator::withOverload` flag (stored in [`modules/interpreter/src/include/Evaluator.hpp`](https://github.com/nelson-lang/nelson/blob/main/modules/interpreter/src/include/Evaluator.hpp)) provides an additional internal check that can disable the entire subsystem when set to `false`.

## Summary

The Nelson type overload system enables custom behaviors through a deterministic runtime lookup mechanism:

- **Naming Convention**: Overload functions reside in `@ClassName/FunctionName.m` files, constructed dynamically by `getOverloadFunctionName` in [`OverloadName.hpp`](https://github.com/nelson-lang/nelson/blob/main/OverloadName.hpp)
- **Runtime Dispatch**: The `callOverloadedFunction` routine in [`OverloadHelpers.hpp`](https://github.com/nelson-lang/nelson/blob/main/OverloadHelpers.hpp) resolves calls by computing common argument types and querying the function table
- **Configuration Control**: Three compatibility levels (`NLS_OVERLOAD_NONE`, `NLS_OVERLOAD_OBJECT_TYPES_ONLY`, `NLS_OVERLOAD_ALL_TYPES`) allow fine-grained control via `NelsonConfiguration`
- **Implementation Pattern**: Create class directories, implement methods following the `@ClassName/function` pattern, and add the directory to the Nelson path

## Frequently Asked Questions

### How does Nelson resolve which overloaded function to call when arguments have different types?

Nelson computes the **common type** of all arguments to determine the overload resolution path. The `callOverloadedFunction` dispatcher in [`OverloadHelpers.hpp`](https://github.com/nelson-lang/nelson/blob/main/OverloadHelpers.hpp) examines the types of all operands, identifies the dominant class, and constructs the overload symbol `@ClassName/FunctionName` based on that common type. If the arguments belong to different user-defined classes, the left-most operand's type typically determines the dispatch according to the interpreter's type precedence rules.

### Can I overload built-in operators like `+` or `-` for existing primitive types?

Yes, but only when the `NLS_OVERLOAD_ALL_TYPES` compatibility level is enabled. By default, Nelson uses `NLS_OVERLOAD_OBJECT_TYPES_ONLY`, which restricts overloading to user-defined classes. To enable primitive type overloading, call `NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_ALL_TYPES)`. However, overloading built-in primitives can impact performance and may cause unexpected behavior in library code, so use this capability cautiously.

### What is the performance impact of using type overloads in Nelson?

The Nelson type overload system introduces a small runtime overhead because every function call must check `Evaluator::withOverload`, compute the common argument type, construct the overload symbol via `getOverloadFunctionName`, and query `FunctionsInMemory` for the M-file existence. For performance-critical sections, you can eliminate this overhead by temporarily setting the compatibility level to `NLS_OVERLOAD_NONE` using `NelsonConfiguration().setOverloadLevelCompatibility()`, which bypasses all overload resolution logic entirely.

### How do I disable overload resolution for debugging purposes?

You can disable the Nelson type overload system globally by setting the compatibility level to `NLS_OVERLOAD_NONE` through the configuration API. Execute `NelsonConfiguration().setOverloadLevelCompatibility(NLS_OVERLOAD_NONE)` to prevent the interpreter from searching for `@ClassName/FunctionName` M-files and force all calls to use built-in implementations. To re-enable overloads later, restore the previous setting or set it to `NLS_OVERLOAD_OBJECT_TYPES_ONLY` or `NLS_OVERLOAD_ALL_TYPES` depending on your requirements.