Functions
Functions are the main way to organize reusable logic in RunMat. You can write named functions in their own files, define helper functions alongside a script, nest functions inside one another to share state, and pass functions around as values with handles. RunMat follows MATLAB's function semantics, so most existing code will run unchanged.
Defining and calling functions
A function declares its outputs, a name, and its inputs. The simplest functions take a few arguments and return one value:
function y = square(x)
y = x * x;
end
disp(square(5)); % 25A function can return multiple values by listing them in brackets. Callers choose how many they want — request all of them, or just the first:
function [s, d] = sumdiff(a, b)
s = a + b;
d = a - b;
end
[s, d] = sumdiff(10, 3); % s = 13, d = 7
s2 = sumdiff(10, 3); % s2 = 13 (second output discarded)Where functions live
A function defined in its own file should be named after the file: square lives in
square.m. Once that file is on a source root, you can call square from any script or
function. RunMat does not auto-run a function file when you execute it the way it runs
a script — the file defines the function, and you call it by name. See
Projects for how source roots are resolved.
You can also define local functions in the same file, after the code that uses them. A script file or a function file may end with a list of additional functions that are visible only within that file:
disp(area(2, 3)); % 6
function a = area(w, h)
a = w * h;
endOptional arguments with nargin
nargin reports how many arguments the caller actually passed, which lets you fill in
defaults:
function y = scale(x, factor)
if nargin < 2
factor = 1;
end
y = x * factor;
end
scale(5) % 5
scale(5, 2) % 10nargout works the same way for outputs, so a function can avoid computing results the
caller did not ask for.
Variable arguments: varargin and varargout
Use varargin to accept any number of trailing arguments. Inside the function it is a
cell array of the extra values:
function n = countargs(varargin)
n = numel(varargin);
end
countargs(1, 2, 3, 4) % 4varargout does the same for outputs, letting a function return a variable number of
values:
function varargout = spread()
varargout{1} = 1;
varargout{2} = 2;
varargout{3} = 3;
end
[a, b, c] = spread(); % a = 1, b = 2, c = 3Recursion
Functions can call themselves:
function y = fact(n)
if n <= 1
y = 1;
else
y = n * fact(n - 1);
end
end
fact(5) % 120Nested functions
A nested function is defined inside another function's body. Unlike a local function, a nested function shares the lexical scope of its parent: it can read and write the parent's variables, and changes are visible back in the parent. This makes nested functions useful for accumulating state or building helpers that close over local data:
function r = runningTotal()
total = 0;
function add(x)
total = total + x; % updates the parent's `total`
end
add(5);
add(7);
r = total; % 12
endAnonymous functions and closures
An anonymous function is written with @(args) expression. It captures the values of any
variables it references at the time it is created — capture is by value, so later
changes to those variables do not affect the handle:
k = 10;
addk = @(x) x + k;
addk(5) % 15
k = 100;
addk(5) % still 15 — k was captured as 10Function handles
A function handle is a first-class value that refers to a function. Create one with @
in front of a function name, or as an anonymous function, then call it like any function
or pass it to other functions:
h = @fact; % handle to the fact function above
h(4) % 24
feval(h, 3) % 6 — call a handle by value
func2str(@sin) % "sin" — recover the name/source of a handleHandles are what make higher-order builtins work. arrayfun applies a handle to each
element of an array, and cellfun applies it to each element of a cell array:
arrayfun(@(x) x^2, [1 2 3]) % [1 4 9]
cellfun(@numel, {'ab', 'cde'}) % [2 3]Persistent and global state
A persistent variable keeps its value between calls to the same function. It is private
to that function and initialized empty on the first call:
function n = bump()
persistent c
if isempty(c)
c = 0;
end
c = c + 1;
n = c;
end
bump(); bump();
bump() % 3A global variable is shared across every function (and the base workspace) that declares
it global with the same name:
global COUNT
COUNT = 0;
tick(); tick();
disp(COUNT); % 2
function tick()
global COUNT
COUNT = COUNT + 1;
endArgument validation with arguments blocks
An arguments block declares the size, class, default value, and validators for a
function's inputs. It runs before the function body, so invalid calls are rejected with a
clear error before any work happens:
function a = area(w, h)
arguments
w (1,1) double {mustBePositive}
h (1,1) double = 1
end
a = w * h;
end
area(2, 3) % 6
area(4) % 4 — h defaults to 1Each declaration can specify, in order:
- a size like
(1,1)or(1,:), - a class such as
doubleorchar, - a brace-enclosed list of validators like
{mustBePositive}, - and a default value with
= value, which also makes the argument optional.
Validation failures raise specific identifiers you can catch — for example a size
mismatch raises RunMat:ArgumentValidationSize:
try
area([1 2], 3); % w must be 1x1
catch e
disp(e.identifier); % RunMat:ArgumentValidationSize
endRunMat ships the common mustBe* validators (such as mustBePositive,
mustBeNonnegative, mustBeInteger, and mustBeNonempty).
Introspection helpers
Functions can inspect their own call context:
nargin/nargout— how many inputs/outputs are in play for the current call.narginchk(min, max)/nargoutchk(min, max)— assert the count is in range, raisingRunMat:NotEnoughInputs(or the too-many counterpart) otherwise.
function y = checked(a, b)
narginchk(2, 2);
y = a + b;
end
checked(1, 2) % 3
checked(1) % error: RunMat:NotEnoughInputsCommand syntax
When you call a function with bare words instead of parentheses, RunMat parses each word as a string argument. These two calls are equivalent:
disp hello % command syntax
disp('hello') % function syntaxCommand syntax is convenient for quick interactive calls; use function syntax whenever you need to pass computed values rather than literal words.
Notes and limitations
- A function file is not auto-executed like a script. Running it defines the function; call the function by name to run it.
- Variables created dynamically by
evalare not statically visible to code compiled later in the same scope. Prefer ordinary assignment when you can. argumentsblocks support size, class, default, and the commonmustBe*validators; more elaborate MATLAB validation forms may not all be available yet.
For how functions fit into RunMat's broader MATLAB compatibility, see MATLAB Language Compatability. For how calls are resolved and dispatched at runtime, see Callable Resolution & Function Dispatch.