Main Content

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 R2019bUpdated CodeR2019a and Earlier

The name local is used as the local function and then a variable. This code errors.

function myfunc
% local is an undefined variable
local(1); % Errors
local = 2; 
disp(local);
end

function local(x)
disp(x)
end

Rename the function local to localFcn.

function myfunc
localFcn(1);
local = 2; 
disp(local);
end

function localFcn(x)
disp(x)
end

This code displays 1 then 2.

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.

BeforeAfter
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.

BeforeAfter
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 R2019bR2019a 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 R2019bUpdated CodeR2019a 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 nest from the import statement, rename local function myfunc/nest.

function myfunc
import pkg.nest 
nest();          

    function newNest
    end
end

This function calls function nest from the import statement.

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 nest is not supported.

function myvarfunc
import pkg.nest  % Errors 
nest = 1
end

Rename variable nest.

function myvarfunc
import pkg.nest  % Errors 
thisNest = 1
end

This function modifies variable nest.

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 R2019bUpdated CodeR2019a and Earlier

Local function nest calls function x from imported package.

function myfunc
x = 1;

    function nest
        % Import function x
        import pkg1.x 
        % Calls pkg1.x 
        x()
    end
end

To use variable x in local function nest, pass the variable as an argument.

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 nest ignores imported function x.

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 R2019bUpdated CodeR2019a and Earlier

This code throws an error when starting MATLAB with the -nojvm option.

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 usejava.

function myfunc 
import java.lang.String % Errors
% Do something with java String class 
end

This code displays a message when starting MATLAB with the -nojvm option.

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 R2019bR2019a 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 R2019bR2019a and Earlier

To evaluate the anonymous function, MATLAB calls the local function lf with x defined in myscript because lf in the anonymous function resolves to 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 lf as an unresolved identifier along with x, and used x to index into the variable lf from myscript.

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 

See Also

Related Topics