Update Code for R2019b Changes to Function Precedence Order
Starting in R2019b, MATLAB changes the rules for name resolution, impacting the precedence order of variables, nested functions, local functions, and external functions. The new rules simplify and standardize name resolution. For more information, see Function Precedence Order.
These changes impact the behavior of the import
function. You should analyze and possibly update your code. To start, search your code for import statements. For example, use Find Files to search for .m
and .mlx
files containing text import
. Refer to these search results when evaluating the effects of the following changes.
Identifiers cannot be used for two purposes inside a function
Starting in R2019b, an error results if you use an identifier, first as a local or imported function, and then as a variable. In previous releases, an identifier could be used for different purposes within the scope of a function, which resulted in ambiguous code.
If this behavior change impacts your code, rename either the variable or the function so that they have different names.
Starting in R2019b | Updated Code | R2019a and Earlier |
---|---|---|
The name function myfunc % local is an undefined variable local(1); % Errors local = 2; disp(local); end function local(x) disp(x) end | Rename the function function myfunc localFcn(1); local = 2; disp(local); end function localFcn(x) disp(x) end | This code displays function myfunc local(1); % local is a function local = 2; disp(local); end function local(x) disp(x) end |
Identifiers without explicit declarations might not be treated as variables
Starting in R2019b, MATLAB® does not use indexing operators to identify the variables in your program. Previously, an identifier without an explicit declaration was treated as a variable when it was indexed with a colon, end
, or curly braces. For example, x
was treated as a variable in x(a,b,:)
, x(end)
, and x{a}
.
Consider the following code. MATLAB used to treat x
as a variable because of colon-indexing. Starting in R2019b, if a function of the same name exists on the path, MATLAB treats x
as a function.
function myfunc load data.mat; % data.mat contains variable x disp(x(:)) end
If you intend to use x
as a variable from data.mat
instead of a function, explicitly declare it. Similarly, to use an identifier x
as a variable obtained from a script, declare it before invoking the script. This new behavior also applies if the variable is implicitly introduced by the functions sim
, eval
, evalc
, and assignin
.
This table shows some examples of how you can update your code.
Before | After |
---|---|
function myfunc load data.mat; disp(x(:)) end | function myfunc load data.mat x; disp(x(:)) end |
function myfunc2 myscript; % Contains variable x disp(x(:)) end | function myfunc2 x = []; myscript; disp(x(:)) end |
Variables cannot be implicitly shared between parent and nested functions
Starting in R2019b, sharing an identifier as a variable between a nested function and its parent function is possible only if the identifier is explicitly declared as a variable in the parent function.
For example, in the following code, identifier x
in
myfunc
is different from variable x
in the
nested function. If x
is a function on the path, MATLAB treats x
in myfunc
as a function and
the code runs. Otherwise, MATLAB throws an error.
function myfunc nested; x(3) % x is not a shared variable function nested x = [1 2 3]; end end
In previous releases, if x
was a function on the path, MATLAB treated it as a function in myfunc
and as a variable in
nested
. If x
was not a function on the path,
MATLAB treated it as a variable shared between myfunc
and
nested
. This resulted in code whose output was dependent on the
state of the path.
To use an identifier as a variable shared between parent and nested functions, you might need to update your code. For example, you can initialize the identifier to an empty array in the parent function.
Before | After |
---|---|
function myfunc nested; x(3) function nested x = [1 2 3]; end end | function myfunc x = []; nested; x(3) function nested x = [1 2 3]; end end |
Change in precedence of wildcard-based imports
Starting in R2019b, imported functions from wildcard-based imports have lower precedence than variables, nested functions, and local functions. In R2019a and earlier, imports in a function shadowed local functions and nested functions.
For example, in this code, the statement local()
calls myfunc/local
instead of pkg1.local
in the wildcard-based import. The statement nest()
calls myfunc/nest
instead of pkg1.nest
.
Starting in R2019b | R2019a and Earlier |
---|---|
function myfunc % Import includes functions local and nest import pkg1.* local() % Calls myfunc/local function nest end nest(); % Calls myfunc/nest end function local end |
function myfunc % Import includes functions local and nest import pkg1.* local() % Calls pkg1.local and % displays warning since R2018a function nest end nest(); % Calls pkg1.nest end function local end |
In the search results for import
, look for statements that include the wildcard character (*
).
Fully qualified import functions cannot have the same name as nested functions
Starting in R2019b, fully qualified imports that share a name with a nested function in the same scope throw an error.
Starting in R2019b | Updated Code | R2019a and Earlier |
---|---|---|
This function errors because it shares a name with a nested function in the same scope. function myfunc import pkg.nest % Errors nest(); function nest end end | To call function function myfunc import pkg.nest nest(); function newNest end end | This function calls function function myfunc import pkg.nest nest(); % Calls pkg.nest function nest end end |
This function errors because declaring a variable with the same name as the imported function function myvarfunc import pkg.nest % Errors nest = 1 end | Rename variable function myvarfunc import pkg.nest % Errors thisNest = 1 end | This function modifies variable
function myvarfunc import pkg.nest nest = 1 % Modifies variable nest and % displays warning since R2018a end |
Fully qualified imports shadow outer scope definitions of the same name
Starting in R2019b, fully qualified imports always shadow outer scope definitions of the same name. In R2019a and earlier, a fully qualified import was ignored when it shadowed an identifier in the outer scope.
Starting in R2019b | Updated Code | R2019a and Earlier |
---|---|---|
Local function function myfunc x = 1; function nest % Import function x import pkg1.x % Calls pkg1.x x() end end | To use variable function myfunc x = 1; nest(x) function nest(x1) % Import function x import pkg1.x % Calls pkg1.x with % variable x1 x(x1) end end | In this code, function function myfunc x = 1; function nest % Import function x import pkg1.x % x is a variable x() end end |
Error handling when import not found
Starting in R2019b, fully qualified imports that cannot be resolved throw an error with or without Java®. In R2019a and earlier, MATLAB behaved differently depending on whether you started MATLAB with the -nojvm
option. Do not use functions like javachk
and usejava
to customize error messages.
Starting in R2019b | Updated Code | R2019a and Earlier |
---|---|---|
This code throws an error when starting MATLAB with the function myfunc import java.lang.String % Errors if ~usejava('jvm') % Statement never executes disp('This function requires Java'); else % Do something with Java String class end end | Remove call to
function myfunc import java.lang.String % Errors % Do something with java String class end | This code displays a message when starting MATLAB with the function myfunc import java.lang.String if ~usejava('jvm') % Display message disp('This function requires Java'); else % Do something with Java String class end end |
Nested functions inherit import statements from parent functions
Starting in R2019b, nested functions inherit import
statements from
the parent function. In R2019a and earlier, nested functions did not inherit import
statements from their parent functions.
Starting in R2019b | R2019a and Earlier |
---|---|
function myfunc % Package p1 has functions plot and bar import p1.plot import p1.* nest function nest plot % Calls p1.plot bar % Calls p1.bar end end |
function myfunc % Package p1 has functions plot and bar import p1.plot import p1.* nest function nest plot % Calls plot function on path bar % Calls bar function on path end end |
Change in precedence of compound name resolution
Starting in R2019b, MATLAB resolves compound names differently. A compound name is comprised of
several parts joined by a dot (for example, a.b.c
), which can be used
to reference package members. With R2019b, MATLAB resolves compound names by giving precedence to the longest matching
prefix. In previous releases, the precedence order followed a more complex set of
rules.
For example, suppose a package pkg
contains a class
foo
with a static method bar
and also a
subpackage foo
with a function bar
.
+pkg/@foo/bar.m % bar is a static method of class foo +pkg/+foo/bar.m % bar is a function in subpackage foo
In R2019b, a call to which pkg.foo.bar
returns the path to the
package function.
which pkg.foo.bar
+pkg/+foo/bar.m
Previously, a static method took precedence over a package function in cases where a package and a class had the same name.
Anonymous functions can include resolved and unresolved identifiers
Starting in R2019b, anonymous functions can include both resolved and unresolved identifiers. In previous releases, if any identifiers in an anonymous function were not resolved at creation time, all identifiers in that anonymous function were unresolved.
Starting in R2019b | R2019a and Earlier |
---|---|
To evaluate the anonymous function, MATLAB calls the local function function myfun myscript; % Includes x = 1 and lf = 10 f = @()lf(x); f() % Displays 'Inside lf' end % Local function to myfun function lf(y) disp('Inside lf'); end | MATLAB considers function myfun myscript; % Includes x = 1 and lf = 10 f = @()lf(x); f() % Displays 10 end % Local function to myfun function lf(y) disp('Inside lf'); end |