Write Z = Y * X' in MATLAB and you are looking at a matrix multiply and transpose. The code reads like the equation on the whiteboard. Engineers who review Kalman filters or finite element assemblies for a living rely on that: if the code matches the derivation, mistakes are visible. If it doesn't, they aren't.
The language was never the part people wanted to leave. MathWorks took MATLAB commercial in 1984, and by the early 1990s it was the standard computational tool in engineering departments. John W. Eaton was finishing his PhD at the University of Texas in 1992 when he and his colleagues, James B. Rawlings (Wisconsin-Madison) and John G. Ekerdt (UT Austin), were writing a chemical reactor design textbook. The faculty used MATLAB for the computational exercises. The students were stuck with Fortran. In his DSC-2001 paper, Eaton wrote that "we eventually decided to implement something that would be mostly Matlab-compatible so that our colleagues could switch to using Octave without having to learn a completely new language." One of the project's explicit goals, as he later told the FSF, was "to liberate the code written for the proprietary program, MATLAB."
The first Octave alpha (version 0.60) shipped on January 4, 1993. Version 1.0 followed in February 1994. Thirty-two years later, Octave 11.1 shipped in February 2026 and the project remains actively maintained. The name honors Octave Levenspiel, a chemical engineering professor known for his textbook on reaction engineering. It has nothing to do with music.
We build RunMat, which is trying to do the same thing with a different engine. We have been working on the same compatibility surface Eaton defined, so everything here comes with that bias.
What "MATLAB compatibility" actually requires
Most people who say "MATLAB compatible" are thinking about syntax: 1-based indexing, column-major storage, the colon operator, A * B for matrix multiply. That part is real but small. The actual surface area is much larger.
MATLAB is a coupled system. The language, the data format, the plotting model, and the command-line semantics all depend on each other. A partial list of what "compatibility" means in practice:
The type system is one example. Every value is an array. Scalars are 1x1 arrays. Strings have historically been char arrays (row vectors of character codes), with a newer string type layered on top. Complex numbers are a property of the array, not a separate type. Logical arrays behave like numeric arrays in arithmetic but have different indexing semantics.
Then there is the OOP layer. MATLAB's classdef system supports properties with validation, methods, events, handle classes (reference semantics), value classes (copy semantics), enumerations, and the ?ClassName metaclass operator for runtime introspection. Codebases written after R2008a increasingly depend on this, and it is one of the hardest subsystems to replicate.
Variadic functions interact with cell array expansion and struct field access in ways that require careful handling of the call stack. [a, b] = deal(x, y) and {c{:}} = func() are both valid and both exercise different code paths.
Indexing is deceptively complex. end inside an index expression computes the size of the relevant dimension, and it composes: A(end-1:end, :) requires the runtime to know which dimension end refers to at each position. Every indexing syntax dispatches through subsref and subsasgn in user-defined classes, whether it is curly-brace access into cells or dot access into structs.
The .mat binary format is another surface. MathWorks has revised it at least five times (v4, v5, v6, v7, v7.3/HDF5), each with different compression and type representation. Real-world codebases contain files saved across decades of MATLAB versions. How much of this a compatible runtime needs to support depends on the use case: production data pipelines increasingly use HDF5 or Parquet directly, but lab environments often still pass .mat files around.
Command syntax creates parser ambiguity. hold on is valid MATLAB. So is hold('on'). The parser needs to distinguish between commands (where arguments are unquoted strings) and function calls (where arguments are expressions), and it resolves the ambiguity using heuristics about what names are known functions. The parser's behavior depends on what's on the path.
MATLAB also maintains global state tracking which figure and axes are current (gcf, gca). Plotting commands like plot, hold, title, and xlabel implicitly target this state. Replicating the plotting model means replicating this stateful architecture.
Any tool that calls itself "MATLAB compatible" is committing to all of this, plus package namespaces (+pkg/ directories), the MException error hierarchy, function handles with closures, and dozens of other subsystems. The syntax is the easy part.
A single function can exercise most of these surfaces at once:
function [peak, idx] = find_peak(data, opts)
results = opts.filters{end}; % cell indexing + end arithmetic
[~, idx] = max(data(end-99:end, :)); % end arithmetic, multiple returns, ~ discard
peak = data(idx, :);
fig = figure; % implicit gcf state
plot(data); hold on % command syntax (unquoted string arg)
plot(idx, peak, 'ro');
title(sprintf('Peak at index %d', idx))
end
Each line depends on a different subsystem. A compatible runtime has to get all of them right simultaneously.
Where Octave made choices that lasted
Octave has been maintained for over three decades. A project that survives that long does so because of specific engineering decisions, not accident. Four of Octave's choices are worth examining because they defined what MATLAB compatibility means in practice.
MAT file support as a compatibility investment
Octave has read/write support for .mat files from version 4 through version 7.3 (HDF5). Getting it right required tracking every revision MathWorks made to the binary format, including changes to compression behavior and Unicode string encoding, plus the complete shift to HDF5 in v7.3. The payoff is that engineers can move .mat files between MATLAB and Octave without conversion, and that interoperability has been one of Octave's strongest adoption drivers. Whether the .mat format remains the right long-term serialization choice is a separate question. HDF5 and Parquet are increasingly common in production pipelines, and newer runtimes may reasonably choose to prioritize those over a proprietary binary specification.
Octave Forge as a distribution model
Before pip or Julia's Pkg existed, Octave Forge provided a curated set of MATLAB-toolbox equivalents with stable naming conventions: signal, image, control, statistics, optim. The system was never as polished as modern package managers. Installing packages involved downloading tarballs and running pkg install. But Octave Forge solved the distribution problem for scientific computing packages years before the rest of the open-source world converged on package management as a standard practice. Octave 11 improved the experience in February 2026 with pkg search for finding packages by keyword and SHA256 verification for downloaded archives, removing the need for the old -forge flag.
A formal grammar via Bison
Octave's parser is generated by GNU Bison from a formal grammar specification. This is a deliberate engineering choice with a clear trade-off. On the positive side, a formal grammar makes it possible to track MATLAB's syntax evolution predictably: when MathWorks adds new syntax, the Octave team can extend the grammar rules rather than patching an ad hoc parser. On the negative side, Bison-generated parsers produce error messages that read like compiler diagnostics, not like REPL feedback. For an interactive tool used by students and engineers who are not compiler specialists, that error quality trade-off is a real cost, and it is a cost Octave has paid for 30+ years in exchange for parser correctness.
GPL as a stability mechanism
Eaton chose the GPL deliberately. In his FSF interview, he said the primary reason was preventing proprietary derivatives. In practice, the GPL has also served as a stability mechanism: Octave has never been acquired, rebranded, relicensed, or had its development redirected by a corporate sponsor. For engineering teams shipping multi-decade projects (defense and energy in particular), the confidence that the tool's license and governance will not change is itself a material property. Octave joined the GNU project in May 1997 and the license has been updated exactly once, from GPLv2 to GPLv3, when the new version was released.
Where MATLAB moved and Octave didn't follow
Octave tracks a moving target. MATLAB has added major language and runtime features over the past decade, and Octave has not matched all of them. Five areas where the gap matters most:
Octave's classdef support is partial. It handles properties, methods, inheritance, and basic handle classes. Events and metaclass queries via ?ClassName remain incomplete, and some handle-class edge cases are missing entirely. For legacy procedural code this is irrelevant. For codebases built around MATLAB's OOP model after roughly R2014b, it is a real constraint.
classdef Sensor < handle
properties
Name string
Value double {mustBeFinite}
end
events
ThresholdExceeded % Octave cannot parse this block
end
methods
function update(obj, v)
obj.Value = v;
if v > 100
notify(obj, 'ThresholdExceeded'); % no-op in Octave
end
end
end
end
% Octave handles: properties, methods, handle inheritance
% Octave cannot handle: events block, notify(), property validation
The JIT experiment did not ship. Octave added experimental JIT compilation using LLVM in version 3.8.0 (December 2013), based on Max Brister's GSoC 2012 work, but it was disabled by default and only accelerated simple loops. The Octave wiki documents the history: LLVM's API kept breaking backward compatibility across minor releases, and the JIT never matured beyond a proof of concept. The code was removed from the Octave source tree entirely in 2021. As a result, Octave remains an interpreter, and loop-heavy code runs 10x to 100x slower than in MATLAB or Julia.
GPU acceleration is absent. MATLAB added GPU support via the Parallel Computing Toolbox in 2010. Octave has not followed. Computations run on CPU only. For workloads where GPU offloading matters (large-scale Monte Carlo and image processing pipelines in particular), this is the gap that sends teams back to MATLAB or to Python's PyTorch/CuPy.
Toolbox coverage has a ceiling. Octave Forge provides solid packages for signal processing, image processing, control systems, and statistics. But MathWorks sells roughly 80 specialized toolboxes and add-on products, and several of the most commercially important ones have no Octave equivalent at all: Simulink, Stateflow, Model-Based Design, Embedded Coder, MATLAB Compiler, Polyspace. These are the products that drive six-figure MATLAB site licenses, and no open-source project has replicated them. This is the gap that actually determines whether a team can leave MATLAB.
The IDE trails MATLAB's. Octave's Qt-based GUI is functional: it has an editor, a file browser, a variable inspector, and a command window. It works. But MATLAB's Live Editor with inline plots, cell evaluation markers, integrated debugger, and documentation tooltips is a generation ahead in UX. For teams who use the IDE heavily, Octave feels dated.
None of this diminishes what Octave is. A free, GPL-licensed, MATLAB-compatible interpreter that has been continuously maintained since 1993 is an extraordinary achievement. The gaps exist because MathWorks has had a billion-dollar revenue base funding development for decades, and Octave has had volunteers.
| Capability | MATLAB | GNU Octave | RunMat |
|---|---|---|---|
classdef OOP (properties, methods, events) | Full | Partial (no events, limited metaclass) | Full |
| JIT compilation | Yes | No (experiment removed 2021) | Tiered (interpreter + Cranelift JIT) |
| GPU acceleration | NVIDIA only (Parallel Computing Toolbox, extra license) | None | Automatic, cross-vendor (Metal, Vulkan, DX12, WebGPU) |
.mat file I/O (v4 through v7.3/HDF5) | Full | Full | Not yet (HDF5 and Parquet prioritized) |
| Browser / WebAssembly | No | No | Yes (client-side via WASM + WebGPU) |
| Toolbox breadth | ~80 toolboxes (Simulink, Stateflow, Embedded Coder, etc.) | Octave Forge (~70 packages) | Growing package system, 400+ builtins |
| Async / non-blocking I/O | parfeval (Parallel Computing Toolbox) | No | Native (entire VM is async) |
| Simulink / graphical modeling | Yes | No | No |
| License | Proprietary, subscription (~$2,000+/seat) | GPL v3, free | MIT, free |
What changed about building a MATLAB runtime
Several engineering constraints that shaped Octave's architecture have shifted since the project was designed. This is not a criticism of the decisions Octave made. A project started in 1992 and built in C++ with the tools available then was working within a different set of possibilities. Six changes matter:
Tiered JIT compilation is proven infrastructure
When Octave experimented with JIT compilation in the early 2010s, the approach was still risky for highly dynamic languages. Since then, V8 (TurboFan), JavaScriptCore, LuaJIT, and Julia's type-inferring compiler have all demonstrated that interpret-first, profile-guided tiered compilation works reliably for languages with dynamic dispatch and runtime polymorphism. The key lesson from these systems is that the JIT has to be designed into the runtime from the start. Bolting a type-specialized compiler onto an existing untyped interpreter, which is roughly what Octave's JIT experiment attempted, is structurally harder than building the intermediate representation to carry shape and type information from day one. RunMat's architecture follows the same tiered model as V8: code starts in an interpreter, hot paths compile to optimized machine code via Cranelift, and the transition is invisible to the user. In practice this means a for loop over a million iterations runs 150x-180x faster than the same loop in Octave.
GPU compute is no longer optional
Both MATLAB and Octave were designed when compute meant CPU. MATLAB's original architecture dates to the 1980s. Octave's dates to 1992. In both, execution is single-threaded and synchronous: one operation finishes before the next one starts. MATLAB added GPU support in 2010 via the Parallel Computing Toolbox, but it requires explicit gpuArray calls, only works with NVIDIA hardware, and costs an additional license. Octave never added GPU support at all.
The reason this matters for numerical computing specifically is that the workloads MATLAB users run (matrix multiplies, FFTs, Monte Carlo simulations, elementwise operations over large arrays) are exactly the kind of embarrassingly parallel, memory-bandwidth-bound work that GPUs were designed to accelerate. A CPU processes these operations sequentially or with a handful of SIMD lanes. A GPU processes thousands of elements simultaneously. For a 10-million-element array operation, the difference is not incremental. It can be 100x.
The hardware is already there. Every laptop ships with a GPU. Apple Silicon unifies CPU and GPU memory. Cloud instances routinely come with accelerators. The bottleneck is not hardware availability. It is that MATLAB and Octave require the user to manually manage GPU transfers, or in Octave's case offer no GPU path at all.
In 2010, GPU computing for engineers meant CUDA on NVIDIA hardware. In 2026, Metal (Apple), Vulkan (Linux/Windows/Android), DirectX 12 (Windows), and WebGPU (browsers) are all mature. A single abstraction layer like wgpu (written in Rust, used by Firefox) can target all of them from one codebase. RunMat uses wgpu to offer automatic GPU acceleration on NVIDIA, AMD, Intel, and Apple hardware, including in the browser via WebGPU. The user writes the same MATLAB code they always wrote. The runtime decides what goes to the GPU, fuses elementwise chains into single kernels, and keeps data resident on-device between operations. On memory-bound workloads the result is measurable: Monte Carlo simulations (5M paths) run ~2.8x faster than PyTorch and ~130x faster than NumPy. Julia's Metal.jl and AMDGPU.jl take a per-vendor approach with separate packages for each backend; Octave has no GPU path at all.
Async-native execution changes what a runtime can do
MATLAB and Octave both run code synchronously: call a function, wait for it to return, move to the next line. That model was fine when all compute was CPU-bound and local. It becomes a bottleneck when a script needs to fetch data from an API, write results to cloud storage, wait for a GPU kernel to finish, or coordinate multiple long-running tasks. In MATLAB, the answer is parfeval and the Parallel Computing Toolbox (another paid add-on). In Octave, there is no answer. The runtime blocks.
RunMat's VM, all builtins, and the GPU provider run on an async substrate. Every evaluation is a Rust future under the hood, even synchronous code (which just completes immediately). This means I/O, GPU dispatch, and network calls are non-blocking by design. The runtime can overlap GPU kernel execution with CPU-side work, stream file reads while processing earlier chunks, and integrate naturally with the Tokio ecosystem for HTTP, websockets, and cloud storage. For existing MATLAB code, nothing changes. The code runs exactly as it always did. But the runtime is not stalling while the GPU finishes or the disk writes.
Memory-safe systems languages are mainstream
Octave is written in C++, started before smart pointers were standardized and before memory sanitizers existed. This is not a criticism of the codebase. It is a statement about what was available. A runtime started in 2023 in Rust or modern C++20 has structurally different memory safety properties: null pointer dereferences and use-after-free bugs are caught at compile time rather than discovered in production. The Rust compiler's borrow checker eliminates entire categories of bugs that C++ projects spend significant testing effort to find. This changes the maintenance economics of a numerical runtime, especially one that ships to security-conscious environments.
WebAssembly is a real deployment target
WebAssembly did not exist in any usable form during Octave's formative decades. WASM 1.0 shipped in browsers in 2017; WASI (the server-side standard) is still maturing. A runtime designed today can compile to WASM and run in the browser from day one, without installing anything or requesting administrator permissions. Octave has no production WebAssembly build. Pyodide brings Python to the browser via WASM but with real performance constraints and no GPU access. RunMat compiles to WASM and ships a full browser IDE with editor, console, plotting, and GPU acceleration. No install, no account, startup in ~5 ms. For a MATLAB-compatible tool, that changes how engineers first encounter it: paste a .m file and run it before deciding whether to install anything.
Tolerance-checked numerical testing is standard practice
QuickCheck-style property-based testing was introduced in 1999 but took roughly twenty years to become standard in numerical libraries. A 2026-era runtime can build its test suite from the start with tolerance-checked parity tests against LAPACK and BLAS references and GPU-vs-CPU parity fuzzing across SIMD widths, publishing per-builtin coverage tables alongside the code. Octave has tests, but retrofitting a 30-year-old test suite with modern numerical fuzzing methodology requires investment that competes with feature development for volunteer time. The result is a difference in how confidently users can evaluate correctness: RunMat publishes a Correctness and Trust page listing every numerical builtin with its implementation source and parity test; Octave's tests are in the source tree but not consolidated into a single auditable reference.
The ceiling for what a MATLAB-compatible runtime can deliver is higher now than when Octave was designed. That ceiling keeps moving. And the argument for keeping MATLAB syntax specifically has only gotten stronger: millions of engineers already know it and decades of course material teach it. The cost of switching languages is not just rewriting code. It is retraining teams and losing the ability to hire someone who can be productive on day one. A modern engine under a familiar language avoids all of that.
What has not changed is that compatibility is hard, the surface area is enormous, and any new entrant inherits both the prior art and the obligation to get the details right.
Where MATLAB still wins
Neither Octave nor RunMat replicates Simulink's graphical block-diagram modeling, and neither is likely to. Simulink and Stateflow are distinct products with their own engineering complexity. Engineers who depend on graphical modeling still need MATLAB or need to rewrite their workflows as scripts. This is the single largest reason MATLAB renewals happen at the enterprise level.
Full toolbox parity is also not a realistic goal. MathWorks sells roughly 80 toolboxes developed by domain specialists over decades. Neither project will replicate all of them. Both projects pick which toolboxes to cover based on user demand. The honest answer for any MATLAB user evaluating free alternatives is: check whether the specific functions your code calls are supported, rather than assuming blanket compatibility.
The IDE story is more nuanced. MATLAB's Live Editor with inline output, cell evaluation, integrated profiler, and breakpoint debugging has had decades of iteration. Octave's Qt GUI is functional but dated. RunMat's editor takes a different approach with a modern browser-based IDE, a first-party VS Code / Cursor extension with LSP-powered diagnostics and completions, and a cloud-based sandbox that runs entirely client-side. The tooling philosophy differs: rather than replicating MATLAB's monolithic IDE, RunMat integrates into the editors engineers already use.
The advantage of choosing MATLAB syntax shows up most clearly in switching costs. MATLAB is taught in engineering programs worldwide, which means any engineer hired off a campus or out of a lab already knows the language. Moving a team to Python or Julia means retraining everyone on an entirely new language and toolchain. Moving a team to Octave or RunMat means the code they already know how to write runs as-is. The language-level friction is near zero. Toolbox gaps and Simulink dependencies are real migration costs, but the language itself is not one of them, and that is a deliberate design choice.
Choosing a free MATLAB-compatible runtime in 2026 is a practical decision, not an ideological one. Use Octave or RunMat where they fit. Keep MATLAB where the toolbox dependency or Simulink requirement makes switching impractical.
Credit where it is due
John W. Eaton built Octave because students were struggling with Fortran and his department needed a free tool that could run the same code as the commercial product the faculty used. That decision, made in 1992, produced a tool that has been continuously maintained for over three decades and is still shipping major releases in 2026. The Octave Forge maintainers built a package distribution system around it before that concept was mainstream. The project has survived changes in computing platforms and multiple generations of competing tools, all without corporate sponsorship or a change in license.
Anyone building a MATLAB-compatible runtime today, including us, is working in a category that Octave defined. What has changed is the toolkit available to build with, not the difficulty of the problem or the value of solving it.
RunMat is what we are building with that toolkit: a JIT-compiled, GPU-accelerated MATLAB-compatible runtime that runs in the browser and on every major OS, MIT-licensed, with 400+ builtins shipping today. If your .m files run, you get automatic GPU acceleration on any vendor's hardware and 150x+ speedups on loop-heavy code with zero code changes. Try it in the sandbox. For a broader comparison including Julia and Python, see the full alternatives guide.
Related posts

MATLAB FFT in RunMat: Frequency Analysis with GPU-Accelerated Plotting
Learn MATLAB FFT online with RunMat. Compute and plot FFT spectra with MATLAB-compatible syntax, including single-sided spectra, windowing, and 2D FFT in the browser.

How to Use GPU in MATLAB Without CUDA: Apple Silicon, NVIDIA, AMD & Intel
A practical guide to GPU acceleration in MATLAB on any hardware. How it works on NVIDIA with the Parallel Computing Toolbox, why it doesn't work on Apple Silicon, AMD, or Intel, and how to get GPU acceleration without CUDA.

MATLAB Plotting in RunMat: Complete Guide to 2D, 3D & GPU-Accelerated Figures
A hands-on guide to plotting in RunMat with 20+ runnable examples covering line plots, scatter, bar charts, 3D surfaces, contour maps, subplots, animations, and GPU-accelerated rendering. All examples run in the browser.
Enjoyed this post? Join the newsletter
Monthly updates on RunMat, Rust internals, and performance tips.
Try RunMat for free
Open the sandbox and start running MATLAB code in seconds. No account required.