Local, Nested and Private Functions
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Written against MATLAB R2026b. The sessions below were run in GNU Octave 11.3.0 (MATLAB code that Octave also accepts) and show Octave’s output with blank lines omitted; the texts of the error messages that MATLAB prints differ and are not run here. Local functions in scripts are described on Scripts and Code Sections; the basics of function files are on Functions.
A program file can hold more than one function, and a folder can hide helpers in a subfolder. The three forms below differ in who may call the helper and in what data it can see: a local function is visible to its own file, a nested function additionally shares the variables of the functions that contain it, and a private function is visible to the folder above its private subfolder. Keeping helpers out of the public interface is the point: the file names on the path stay few and meaningful, and a helper can be changed without breaking callers elsewhere.
Local functions
In a function file, the first function is the main function and the others are local functions (called subfunctions in older releases). Local functions can follow the main function in any order, and only the functions of the same file can call them. They are the usual way to split a task into steps.
function [T, nIter] = relaxPlate(T, tol)
% RELAXPLATE Jacobi sweeps on the interior of T until the update is below tol.
nIter = 0;
delta = Inf;
while delta > tol && nIter < 1000
Tnew = sweep(T);
delta = maxChange(Tnew, T);
T = Tnew;
nIter = nIter + 1;
end
end
function Tnew = sweep(T)
Tnew = T;
Tnew(2:end-1, 2:end-1) = (T(1:end-2, 2:end-1) + T(3:end, 2:end-1) ...
+ T(2:end-1, 1:end-2) + T(2:end-1, 3:end)) / 4;
end
function d = maxChange(A, B)
d = max(abs(A(:) - B(:)));
end
T = zeros(5); T(:,1) = 100;
[T, n] = relaxPlate(T, 1e-3);
n
round(T(3,:)*100)/100
try, sweep(T), catch err, disp(err.message), end
Octave 11.3.0 output:
n = 28
ans =
100.0000 52.6800 25.0000 9.8200 0
'sweep' undefined near line 5, column 6
The main function relaxPlate is public: it is the name of the file. sweep and maxChange are local: calling sweep from the Command Window or from another file fails with an undefined-function error (identifier MATLAB:UndefinedFunction, wording varies by release, not run here).
Rules and properties of local functions:
-
They have their own workspaces. A local function cannot see the variables of the main function or of other local functions; everything it needs is passed as an input.
-
They take precedence over functions with the same name in other files, because MATLAB looks for local functions before other main functions. A file can therefore carry its own version of a helper while the original stays untouched elsewhere (see Function Precedence and Name Resolution).
-
endis required if any function in the file contains a nested function, and in scripts. In function files with local functions only, either style works as long as it is used consistently; useendalways. -
Help is available through the file.
help relaxPlate>sweepprints the help text of the local function: the file name, a>character and the local name. -
localfunctionsreturns a cell array of function handles to all local functions of the calling file. Test files written as function-based unit tests use it so that the framework can find the tests (see Unit Testing with matlab.unittest). -
Local functions in scripts (R2016b) can be anywhere in the script since R2024a, but not inside
if,foror other conditional contexts. Before R2024a they had to be at the end. -
A local function need not validate its inputs: the caller is in the same file, so argument validation (see Argument Validation) is usually left to the main function.
Nested functions
A nested function is completely contained within another function, its parent. Its distinguishing property is that it reads and writes the variables of its parents without receiving them as inputs. That makes nested functions the tool for callbacks that share state and for functions that return a handle with data captured inside it.
function countSteps
count = 0;
step(); step(); step();
fprintf("count = %d\n", count);
function step
count = count + 1;
end
end
Here step increments count, which belongs to the workspace of countSteps. The variable need not appear in any argument list.
Octave 11.3.0 output:
count = 3
Rules for nested functions
-
Every function in the file needs
end. A file that contains a nested function must close all of its functions withend. -
They cannot appear inside control statements such as
if,switch,for,whileortry. -
Call them by name or through a handle created with
@.fevalandstr2funcdo not work with a nested function. -
The workspace is static. All variables of a nested function and of its parents must be defined explicitly in the code. A nested function cannot call a script,
eval,loadorevalinto create new variables, and the parent cannot either; such code fails because the variable does not already exist in the workspace (MathWorks documents this error as "Attempt to Add Variable to a Static Workspace"). -
Argument validation (
argumentsblocks) is not allowed in nested functions, per the argument validation documentation. -
A shared variable is shared only if the parent uses it. If the parent function never assigns or refers to a name that two sibling nested functions each assign, every sibling gets its own local variable with that name and they cannot interact.
-
A variable is shared whether it is assigned before or after the nested definition. The position of the nested function in the file does not matter; the parent’s workspace includes its inputs, outputs and all variables assigned anywhere in the parent.
-
Outputs of a nested function are not in the parent’s workspace unless the parent requests them (
z = nestedFcn;).
Handles that carry data
When a parent returns a handle to a nested function, the handle stores not only the function name but also the values of the parent variables that the nested function uses. Each call to the parent creates a new set of such variables, so several handles from the same parent are independent. The captured variables are cleared when the last handle created by that call is cleared.
function h = makeLine(slope, offset)
h = @line;
function y = line(x)
y = slope * x + offset;
end
end
f = makeLine(2, 1);
f(10)
Octave 11.3.0 output:
ans = 21
In the heatflow scenario this is how a boundary condition can carry its parameters (a fixed temperature, a convection coefficient) into the solver as a one-argument function. Anonymous functions (see Anonymous Functions and Function Handles) do the same for a single expression, with the difference that an anonymous function captures a snapshot of the variables at creation time, while a handle to a nested function shares the live variables of its parent.
Visibility among nested functions
A nested function is visible to:
-
the function that contains it (one level up);
-
the other functions nested at the same level in the same parent;
-
the functions nested in those siblings (any lower level).
So a function cannot call a function nested more than one level below it. If A contains B and D, and C is nested in B and E in D, then A can call B and D but not C or E; B can call D (and D can call B); C can call B and D but not E. Other files cannot call any of them. The easiest way to extend the reach of a nested function is to return a handle to it, as above. Only a function that can call a nested function can create a handle to it. The diagram below shows these rules together with those for local and private functions.
Private functions
A function stored in a subfolder named private is visible only to the functions and scripts in the folder immediately above it (and to the other functions in the same private folder). It cannot be called from the Command Window or from any other folder. Do not add the private folder to the path.
The sessions below use a folder named p2, under the current folder, that contains limitTemp.m and a private subfolder with clampTemp.m. The session adds p2 (not p2/private) to the path, building the folder name with fullfile.
function y = clampTemp(x, lo, hi)
% CLAMPTEMP Private helper: limit x to the interval [lo, hi].
y = min(max(x, lo), hi);
end
function y = limitTemp(x)
% LIMITTEMP Public function that uses a private helper.
y = clampTemp(x, 0, 100);
end
addpath(fullfile(pwd, "p2"));
limitTemp([-5 50 120])
try, clampTemp(5, 0, 1), catch err, disp(err.message), end
Octave 11.3.0 output:
ans =
0 50 100
'clampTemp' undefined near line 3, column 6
Properties of private functions:
-
They have precedence over public functions of the same name, so MATLAB finds a private
test.mbefore a non-privatetest.m. A folder can carry its own version of a function while the original stays elsewhere. -
Help is available:
help private/clampTemp, when the current folder is the parent. -
They are plain function files, with their own workspace and any number of local functions. The tools that work with files (the Editor, the debugger,
which) treat them as files in a folder. -
They cannot be tested directly from outside the parent folder, so tests exercise them through the public functions that call them.
-
Classes and namespaces have their own folder forms (
@class,+namespace); see Namespaces and Class Folders.
Which function can call which
The diagram uses one folder with a public file, a second public file, a private subfolder and the command line. Solid arrows are calls that work; dashed arrows are calls that fail.
The rows of the table summarise the same rules.
| Caller | Can call a local function | Can call a nested function | Can call a private function |
|---|---|---|---|
Command Window, function in another folder |
No |
No (only through a returned handle) |
No |
Another file in the same folder |
No |
No (only through a returned handle) |
Yes |
Another function in the same file |
Yes |
If it is the parent, a sibling or a function nested below them |
Yes, if the file is in the parent folder |
A nested function |
Yes (local functions of the file) |
Yes, under the visibility rules above |
Yes, if the file is in the parent folder |
A function in the |
No (it is in another file) |
No |
Yes, the other functions of the same |
When to use each
| Form | Use it when | Avoid it when |
|---|---|---|
Local function |
A helper belongs to one file and needs only the values passed in. This is the default way to break a function into steps. |
Several files need the helper, or the helper is large enough to deserve its own tests and help. |
Nested function |
Callbacks, or a returned handle, must share state with the function that created them. App Designer apps and programmatic UIs use this form. |
The state is large or the sharing is not essential. Shared variables hide data flow; passing inputs and outputs is clearer. |
Private function |
Several public functions in a folder share a helper that should not be public. The helper is large enough for its own file. |
Only one file uses it (a local function is simpler), or the helper is part of the public interface. |
Public function in its own file |
Callers outside the folder need it. |
The helper would clutter the path or the namespace with a name that nobody should call. |
A good order of preference is: pass data explicitly with a local function, use a private function when more than one file shares it, and use a nested function only when the shared state is the point.
Pitfalls
-
Calling a local function from the command line. It is not visible; test it through the main function, or temporarily move it to its own file.
-
Sibling nested functions that assign the same name each get their own variable unless the parent also uses the name.
-
Forgetting
endin a file with a nested function. A single function withoutendmakes the file invalid. -
Using
eval,loador a script inside a nested function or its parent to create variables, which fails because the workspace is static. Load into a structure instead (S = load("plate.mat")). -
A private function that shadows a public one. The private version wins inside the parent folder;
which -all nameshows the order. -
Calling a nested function by
feval("name")orstr2func("name"). Use a direct call or an@handle. -
Large parent workspaces captured by handles. The handle keeps the variables the nested function uses alive; clear the handle when it is no longer needed.
Where older books differ
Older books call local functions subfunctions and show them only in function files; the term local function and local functions in scripts (R2016b, anywhere in the script since R2024a) are newer. They describe the private folder as it is today. Nested functions are covered thinly in older books, which tend to use global variables to share data between callbacks; nested functions or object properties are the modern alternatives (see Workspaces, Scope, Global and Persistent). Argument validation (R2019b) is available in main and local functions but not in nested functions.