How to Integrate Julia Code in Nelson Using the julia_engine Module

Use the jlrun and jlrunfile functions from the julia_engine module to execute Julia expressions and scripts directly within Nelson, passing data via name-value pairs and retrieving results as Nelson variables.

The nelson-lang/nelson repository provides a native julia_engine module that embeds a full Julia runtime inside the Nelson interpreter. This integration allows you to seamlessly integrate Julia code in Nelson, enabling you to execute arbitrary Julia expressions, run external scripts, and exchange data between the two environments without leaving the Nelson console.

Architecture of the julia_engine Module

The integration works through a thin C++ bridge that loads the Julia shared library and manages data conversion between Nelson's ArrayOf type and Julia's native types.

Engine Initialization

When you first call a Julia function, the engine initializes automatically via initializeJuliaEngine in modules/julia_engine/src/cpp/JuliaEngine.cpp. This process:

  1. Checks if the Julia library is already loaded
  2. Reads standardInOutRedirection.jl to redirect Julia's stdout/stderr to Nelson's console
  3. Starts the Julia runtime via NLSjl_init

The module loader in modules/julia_engine/loader.m registers the julia_engine module at Nelson startup unless --without_julia is passed.

Data Flow and Variable Conversion

When you execute Julia code, the following data flow occurs:

  1. Input: Name-value pairs from Nelson become global variables in Julia's Main module via jl_create_main_global_variable
  2. Execution: The code evaluates via NLSjl_eval_string (for strings) or include() (for files)
  3. Output: Requested variables are retrieved from Main using NLSjl_get_global and converted to ArrayOf via jl_value_tToArrayOf in JuliaTypesHelpers.cpp

Executing Julia Code with jlrun

The jlrun function provides the primary interface for executing Julia expressions from Nelson.

Running Simple Expressions

To execute a Julia expression and capture the result:

% Execute a Julia command that returns a matrix
M = jlrun('reshape(1:9, 3, 3)', ["M"]);
disp(M);

The jlrunBuiltin.cpp file handles argument parsing, separating the code string from output variable names and name-value pairs, then forwards to JuliaRun.cpp for execution.

Passing Data from Nelson to Julia

You can pass Nelson variables to Julia using name-value pairs:

% Create a Nelson array
A = int64([1; 2; 3]);

% Pass it to Julia and retrieve a transformed version
B = jlrun('B = A .* 2', ["B"], "A", A);
disp(B);

In this example:

  • "A", A creates a Julia global variable A containing the Nelson data
  • The Julia code computes B = A .* 2
  • "B" in the output list requests retrieval of the B variable back to Nelson

Running Julia Scripts with jlrunfile

For larger Julia programs, use jlrunfile to execute entire scripts:

% Run the script and retrieve three variables A, B, C
[a, b, c] = jlrunfile('test_jlrunfile.jl', ["A","B","C"]);

The jlrunfileBuiltin.cpp interface parses the filename and arguments, then JuliaRunFile.cpp executes the script using Julia's include() function. The implementation follows the same variable injection and retrieval pattern as jlrun.

Consider this example script:


# test_jlrunfile.jl

A = [1;2;3];
B = [4;5;6];
C = [15.0 25.0 35.0; 17.0 27.0 37.0; 19.0 29.0 39.0];
println("Hello from Julia")
println(C)

After execution, a, b, and c contain the respective arrays in Nelson's native format.

Configuring the Julia Environment with jlenv

Before executing any Julia code, you can control which Julia installation Nelson uses via jlenv:

% Query current environment
env = jlenv()

% Change to a custom Julia executable
jlenv('Version', '/opt/julia-1.11.0/bin/julia');

The jlenv.m function in modules/julia_engine/functions/jlenv.m detects the current Julia environment, performs version and architecture checks, and updates the internal JuliaEnvironment singleton. Important: You must call jlenv before the first Julia execution, as the library cannot be unloaded or switched once initializeJuliaEngine has loaded the shared library.

Complete Example: Differential Equations

The repository includes a practical example demonstrating real-world Julia package usage:

% Run a Julia script that solves the Lotka-Volterra system
jlrunfile('example_DifferentialEquations.jl');

The script example_DifferentialEquations.jl installs the DifferentialEquations package, solves an ODE system, and prints results. All standard output appears in the Nelson console, allowing seamless integration of Julia's scientific computing ecosystem into Nelson workflows.

Summary

  • The julia_engine module embeds a full Julia runtime inside Nelson via a C++ bridge in JuliaEngine.cpp.
  • Use jlrun to execute Julia expressions and jlrunfile to run complete scripts, both supporting bidirectional data transfer via name-value pairs.
  • Data conversion happens automatically through JuliaTypesHelpers.cpp, translating between Nelson ArrayOf and Julia types.
  • Configure the Julia installation using jlenv before first execution to specify custom executables or library paths.
  • The integration supports complex workflows including package installation and scientific computing, as demonstrated in the example_DifferentialEquations.jl sample.

Frequently Asked Questions

How do I pass multiple variables from Nelson to Julia?

Use consecutive name-value pairs in jlrun or jlrunfile. For example: jlrun('C = A + B', ["C"], "A", A, "B", B). The C++ layer in JuliaRun.cpp creates corresponding globals in Julia's Main module for each pair.

Can I switch Julia versions after Nelson has started the engine?

No. Once initializeJuliaEngine in JuliaEngine.cpp loads the Julia shared library, the runtime cannot be unloaded or switched. You must call jlenv to configure the path before executing any Julia code, or restart Nelson to change versions.

What Julia types are supported for data exchange?

The conversion layer in JuliaTypesHelpers.cpp handles primitive numeric types, arrays, and matrices. Complex numbers and strings are also supported. When you request an output variable, jl_value_tToArrayOf converts the Julia object back to Nelson's native ArrayOf structure.

How do I capture standard output from Julia scripts?

Standard output redirection happens automatically via standardInOutRedirection.jl, which the engine loads during initialization in JuliaEngine.cpp. Any println or print statements in your Julia code appear directly in the Nelson console without additional configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →