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:
- Checks if the Julia library is already loaded
- Reads
standardInOutRedirection.jlto redirect Julia's stdout/stderr to Nelson's console - 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:
- Input: Name-value pairs from Nelson become global variables in Julia's
Mainmodule viajl_create_main_global_variable - Execution: The code evaluates via
NLSjl_eval_string(for strings) orinclude()(for files) - Output: Requested variables are retrieved from
MainusingNLSjl_get_globaland converted toArrayOfviajl_value_tToArrayOfinJuliaTypesHelpers.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", Acreates a Julia global variableAcontaining the Nelson data- The Julia code computes
B = A .* 2 "B"in the output list requests retrieval of theBvariable 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
jlrunto execute Julia expressions andjlrunfileto run complete scripts, both supporting bidirectional data transfer via name-value pairs. - Data conversion happens automatically through
JuliaTypesHelpers.cpp, translating between NelsonArrayOfand Julia types. - Configure the Julia installation using
jlenvbefore 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.jlsample.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →