Workspaces, Scope, Global and Persistent Variables
|
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 functions and sessions below were run in GNU Octave 11.3.0 (the code is valid MATLAB too) and show Octave’s output; Octave’s who and display layouts differ from MATLAB’s. matlab.lang.Workspace (R2025a) and mlock are not run here and are checked against the R2026b documentation.
Every variable lives in a workspace, a table of names and values, and the rules about which code can see which workspace are the rules of variable scope. Looking at the base workspace (who, whos, clear, save) is on Workspace Variables and MAT-Files; this page is about how workspaces relate to each other and how data moves between them.
The base workspace and function workspaces
The base workspace holds the variables you create at the command line and in scripts that you run from the command line or the Editor. They exist until you clear them or end the session. Every function has its own workspace, separate from the base workspace and from every other function, even from the other local functions in the same file. A variable created in a function belongs to that function’s workspace and disappears when the call ends; its inputs are copies (see the copy-on-write remark below) bound to the input names.
Two exceptions to "one workspace per piece of code":
-
Scripts have no workspace of their own. A script runs in the workspace of whoever runs it: the base workspace when it is run from the command line, the function’s workspace when a function calls it. That is why a script can read and overwrite your variables, and why a function that calls a script is hard to reason about.
-
Nested functions have their own workspace, but they can also use the variables of the functions that contain them (see below).
In the figure the solid arrows are the safe ways to share data (arguments and results), and the dotted links are the global workspace, reachable from any workspace that declares the variable.
Sharing data: arguments first
The most secure way to extend the scope of a variable is to pass it in as an argument and return it as an output. The function states what it reads and what it produces, so it can be tested alone, and no other code can change a value behind its back. Inputs are passed by value, but MATLAB does not copy the data until the function modifies it (copy-on-write), so passing a large array is cheap.
A nested function can read and modify the variables of its parent function without arguments, which is useful when subroutines share state. The sharing applies only to variables that the parent also uses: if the parent does not define x, each nested function that assigns x gets its own private copy.
function sumNested()
total = 0;
add(3); add(4);
disp(total)
function add(k)
total = total + k;
end
end
Octave 11.3.0 prints 7: both calls to add updated the total of the parent. Variables used in a nested function must be explicitly defined in the parent; a nested function cannot create a variable in the parent by calling a script or eval.
persistent variables
A variable declared persistent inside a function keeps its value from one call to the next. It is local to that function (no other code sees it) but it is not destroyed when the call ends: the counterpart of a static variable in other languages. Declare it before using it. MATLAB initialises a persistent variable to the empty matrix [], so the usual idiom is to test with isempty and assign the first value:
function n = countCalls()
persistent calls
if isempty(calls)
calls = 0;
end
calls = calls + 1;
n = calls;
end
The persistent values of a function are cleared by clear all, by clear functions, by clear functionname and by editing the function file; they survive clear of the base workspace’s variables. To keep them, lock the function in memory with mlock (inside the function) and release it with munlock; mislocked tells whether a function is locked. A locked function keeps its persistent variables until MATLAB exits or it is unlocked. Persistent state is a good fit for caches and counters. It is hidden state, though, so a function that depends on it is harder to test: prefer an output argument or a handle object when the state belongs to the caller.
global variables and why to avoid them
A global variable has its own workspace, shared by every piece of code that declares it. The global statement must appear in each workspace (function or command line) that wants to use it, before the variable is used there. Without the declaration, the same name is just a local variable. Assigning a global at the command line after a function has declared it makes the same variable visible; the command isglobal("name") tells whether the name is declared global in the current workspace.
function bumpGlobal()
global heatflowStepCount
heatflowStepCount = heatflowStepCount + 1;
end
The session below uses the persistent function countCalls above and the global one bumpGlobal, then shows the base workspace seen from a function that uses who, assignin and evalin (see the next section). The function touchBase is listed after the output.
x = 1;
countCalls(); countCalls();
n = countCalls()
clear functions
n = countCalls()
global heatflowStepCount
heatflowStepCount = 0;
bumpGlobal(); bumpGlobal();
heatflowStepCount
basevar = 7;
touchBase()
fromfn
exist("y", "var")
isglobal("heatflowStepCount")
clear heatflowStepCount
exist("heatflowStepCount", "var")
clear global heatflowStepCount
global heatflowStepCount
heatflowStepCount
Octave 11.3.0 output:
n = 3
n = 1
heatflowStepCount = 2
{
[1,1] = y
}
base basevar = 7
fromfn = 10
ans = 0
ans = 1
ans = 0
heatflowStepCount = [](0x0)
Reading it from the top: the third call returned 3, and after clear functions the persistent counter started again at 1. The two calls of bumpGlobal raised the global to 2. exist("y","var") is 0: the variable y that touchBase created lives only in that function. clear heatflowStepCount removes the local link to the global (exist is 0 afterwards) but not the global itself, which only clear global heatflowStepCount (or clear all) deletes; after that, declaring it again gives an empty [].
The risks the documentation lists are real. Any function can update a global, so other functions that read it may return unexpected results; and giving a new global the same name as an existing one overwrites the value the other code expects, an error that is difficult to diagnose. The documentation’s advice is to use globals sparingly, if at all, and its example shows the alternative: a function falling(t,gravity) that takes the constant as an input instead of reading a global GRAVITY. For the heatflow scenario that means passing the grid and the boundary kinds to the solver rather than keeping global GRID; a settings structure or a handle object is the next step up. If you do use a global, give it a long, distinctive name (heatflowStepCount, not count) and declare it in as few places as possible.
evalin and assignin as last resorts
assignin(ws, name, value) and evalin(ws, expression) write to and evaluate in another workspace. The workspace is "base" (the base workspace) or "caller" (the workspace of the code that called the current function). They are the tools of last resort, for example in a GUI callback that lists the variables of the base workspace with evalin("base","who"). Like globals they can overwrite existing data without warning, and they make a function depend on a hidden caller, so use argument passing otherwise. The function below, run after the output above, creates a local y, lists its own workspace, writes a result into the base workspace and reads a base variable:
function touchBase()
y = 5;
disp(who)
assignin("base", "fromfn", y*2);
v = evalin("base", "basevar");
fprintf("base basevar = %d\n", v);
end
The output is in the listing above: who inside the function names only y, fromfn appears in the base workspace, and the base variable basevar was readable through evalin. See eval and Its Alternatives for why eval, evalin and assignin are discouraged.
Workspace objects: matlab.lang.Workspace (R2025a)
Since R2025a, matlab.lang.Workspace objects hold a copy of the variables of a workspace, so that code can inspect or pass them around as a value:
-
wBase = matlab.lang.Workspace.baseWorkspacecopies the variables of the base workspace (including those that scripts create when run from the command line or Editor). -
wCurrent = matlab.lang.Workspace.currentWorkspacecopies the variables of the workspace it is called from; called inside a function, it gives that function’s workspace. -
wGlobal = matlab.lang.Workspace.globalWorkspacecopies the global variables.
Because the object holds copies, changing the object does not change the live workspace. Not run here; the class has methods to read, add and remove variables, listed on its reference page and not described further because they could not be checked in this environment. Code that must run on releases before R2025a uses who, evalin and save instead.
Pitfalls
-
A script overwrites your variables, because it runs in the caller’s workspace. Wrap reusable code in a function.
-
clear allclears persistent variables and the functions in memory, which also slows the next run; useclearof specific names,clearvars, orclear functionson purpose (see Workspace Variables and MAT-Files). -
A missing
globaldeclaration in one function silently makes the name a new local variable. -
Name collisions between globals are hard to diagnose; avoid short names.
-
Persistent state makes tests order-dependent. Reset it with
clear functionsbetween tests. -
Editing a function file clears its persistent variables, unless the function is locked with
mlock. -
A variable cannot be created in the parent by a nested function that only calls a script or
eval: variables must be defined explicitly. -
evalin("caller",...)ties a function to its caller’s variable names.
Where older books differ
Older books use global freely to share parameters between functions, and show assignin and evalin in examples as ordinary tools. The scope rules are unchanged, but the current documentation recommends arguments and outputs, nested functions or objects, and treats globals and evalin as risky. matlab.lang.Workspace (R2025a) and the editor’s message about unused variables are newer. Books usually do not mention mlock when they present persistent.