Code Patterns for subsref and subsasgn Methods
For R2021b and later, the recommended process for customizing indexing is to
use the modular indexing superclasses instead of overloading subsref
and subsasgn
. For more information, see Customize Object Indexing.
Customize Indexed Reference and Assignment
User-defined classes have the same indexing behaviors as that of built-in classes.
Classes can customize indexing operations by overloading the functions that MATLAB® calls to evaluate indexing expressions. Overload the subsref
and subsasgn
functions when you want to define
special behaviors for indexed reference and assignment.
Syntax for subsref and subsasgn Methods
MATLAB calls the subsref
and subsasgn
methods of your class with these arguments.
Method | Input | Output |
---|---|---|
|
|
|
|
|
|
Modifying Number of Arguments
If your class design requires that indexing operations return or assign a different number of values than the number defined by the default indexing operation, overload the numArgumentsFromSubscript
function to control nargout
for subsref
and nargin
for subsasgn
. For more information and examples, see numArgumentsFromSubscript
.
Indexing Structure Describes Indexing Expressions
The indexing structure contains information that describes the indexing expression. Class methods use the information in the indexing structure to evaluate the expression and implement custom behavior.
For example, the CustomIndex
class defines a property that you can use in indexing expressions.
classdef CustomIndex properties DataArray end end
Create an object and assign a 5-by-5 matrix created by the magic
function to the DataArray
property.
a = CustomIndex; a.DataArray = magic(5);
This subscripted reference expression returns the first row of the 5-by-5 matrix.
a.DataArray(1,:)
ans = 17 24 1 8 15
This expression assigns new values to the first row of the array stored in the DataArray
property.
a.DataArray(1,:) = [1 2 3 4 5];
This assignment statement uses:
A
'.'
type referenceA property name following the dot (that is,
DataArray
)A range of indices (
1,:
) within parentheses
The indexing structure contains this information in the type
and subs
fields.
Values of the Indexing Structure
When executing an indexing expression, MATLAB calls the class subsref
or subsasgn
method, if the class overloads these functions. One of the arguments passed to the method is the indexing structure. The indexing structure has two fields:
type
— One of the three possible indexing types:'.'
,'()'
,'{}'
subs
— Achar
vector with the property name or cell array of the indices used in the expression, including:
andend
.
If the indexing expression is a compound expression, then MATLAB passes an array of structures, one struct
for each level of indexing. For example, in this expression:
a.DataArray(1,:)
the indexing structure array S
has these values:
S(1).type
is set to'.'
, indicating that the first indexing operation is a dot.s(1).subs
is set to the property name,'DataArray'
The second level of indexing is in the second element of the indexing structure:
S(2).types
is set to'()'
indicating the second indexing operation is parentheses indexingS(2).subs
is set to a cell array containing the indices{[1],[:]}
Typical Patterns for Indexing Methods
To overload the subsref
and subasgn
functions:
Determine the full indexing expression using the
types
andsubs
fields of the indexing structure.Implement the specialized behaviors for the indexing operations supported by the class.
Return the appropriate values or modified objects in response to the call by MATLAB.
A switch
statement is a convenient way to detect the first level of indexing. There are three types of indexing—dot, parentheses, and braces. Each case
block in the switch
statement implements all indexing expressions that begin with that first-level type of indexing.
The methods must implement all indexing expressions that the class supports. If you do not customize a particular type of indexing, call the built-in function to handle that expression.
Use the length of the indexing structure array and indexing type define conditional statements for compound indexing expressions.
Code Framework for subsref
Method
The following framework for the subsref
method shows how to use information in the indexing structure in conditional statements. Your application can involve other expressions not shown here.
function varargout = subsref(obj,s) switch s(1).type case '.' if length(s) == 1 % Implement obj.PropertyName ... elseif length(s) == 2 && strcmp(s(2).type,'()') % Implement obj.PropertyName(indices) ... else [varargout{1:nargout}] = builtin('subsref',obj,s); end case '()' if length(s) == 1 % Implement obj(indices) ... elseif length(s) == 2 && strcmp(s(2).type,'.') % Implement obj(ind).PropertyName ... elseif length(s) == 3 && strcmp(s(2).type,'.') && strcmp(s(3).type,'()') % Implement obj(indices).PropertyName(indices) ... else % Use built-in for any other expression [varargout{1:nargout}] = builtin('subsref',obj,s); end case '{}' if length(s) == 1 % Implement obj{indices} ... elseif length(s) == 2 && strcmp(s(2).type,'.') % Implement obj{indices}.PropertyName ... else % Use built-in for any other expression [varargout{1:nargout}] = builtin('subsref',obj,s); end otherwise error('Not a valid indexing expression') end
Using varargout
for the returned value enables the method to work with object arrays. For example, suppose that you want to support the return of a comma-separated list with an expression like this one:
[x1,...xn] = objArray.PropertyName(Indices)
This expression results in a two-element indexing structure array. The first-level type is dot ('.'
) and the second level is parentheses ('()'
). Build the varargout
cell array with each value in the array.
case '.' ... if length(s)==2 && strcmp(s(2).type,'()') prop = s(1).subs; % Property name n = numel(obj); % Number of elements in array varargout = cell(1,n); % Preallocate cell array for k = 1:n varargout{k} = obj(k).(prop).(s(2).subs); end end ... end
subsasgn Pattern
The following framework for the subsasgn
method shows how to use the indexing structure in conditional statements that implement assignment operations.
function obj = subsasgn(obj,s,varargin) % Allow subscripted assignment to uninitialized variable if isequal(obj,[]) % obj = ClassName.empty; end switch s(1).type case '.' if length(s) == 1 % Implement obj.PropertyName = varargin{:}; ... elseif length(s) == 2 && strcmp(s(2).type,'()') % Implement obj.PropertyName(indices) = varargin{:}; ... else % Call built-in for any other case obj = builtin('subsasgn',obj,s,varargin{:}); end case '()' if length(s) == 1 % Implement obj(indices) = varargin{:}; elseif length(s) == 2 && strcmp(s(2).type,'.') % Implement obj(indices).PropertyName = varargin{:}; ... elseif length(s) == 3 && strcmp(s(2).type,'.') && strcmp(s(3).type,'()') % Implement obj(indices).PropertyName(indices) = varargin{:}; ... else % Use built-in for any other expression obj = builtin('subsasgn',obj,s,varargin{:}); end case '{}' if length(s) == 1 % Implement obj{indices} = varargin{:} ... elseif length(s) == 2 && strcmp(s(2).type,'.') % Implement obj{indices}.PropertyName = varargin{:} ... % Use built-in for any other expression obj = builtin('subsasgn',obj,s,varargin{:}); end otherwise error('Not a valid indexing expression') end end
Using varargin
for the right-side value of the assignment statement enables the method to work with object arrays. For example, suppose that you want to support the assignment of a comma-separated list with an expression like this one:
C = {'one';'two';'three'}; [objArray.PropertyName] = C{:}
This expression results in an indexing structure with the dot type ('.'
) indexing The cell array C
on the right side of the assignment statement produces a comma-separated list. This code assigns one list item to each property in the object array.
case '.' if length(s)==1 prop = s(1).subs; % Property name n = numel(obj); % Number of elements in array for k = 1:n obj(k).(prop) = varargin{k}; end end end
Subscripted Assignment with an Uninitialized Variable
Assigning to an element of an uninitialized variable results in a call to the subsasgn
method of the class on the right side of the assignment. For example, this class defines a subsasgn
method that simply calls the built-in subsasgn
method for parenthesis indexing.
classdef MyClass methods function obj = subsasgn(obj,s,varargin) switch s(1).type case '()' obj = builtin('subsasgn',obj,s,varargin{:}); end end end end
When attempting to assign an object of MyClass
to the first element of the uninitialized variable, B(1)
in the following statement, MATLAB calls the subsasgn
method of MyClass
with an empty double ([]
) as the first argument. The assignment can cause an error because the subsasgn
method must be passed an object of the class.
clear B
B(1) = MyClass;
The following error occurred converting from MyClass to double: Conversion to double from MyClass is not possible. Error in MyClass/subsasgn (line 6) obj = builtin('subsasgn',obj,s,varargin{:});
The subsasgn
method can detect this situation and take the appropriate action, such as returning a useful error message if the class does not support this type of assignment, or converting the input to an object of the class and passing it to subsasgn
.
For example, because MyClass
can allow subscripted assignment to an uninitialized variable, the subsasgn
method can change the first argument from the empty double to an empty MyClass
object.
Use the isequal
function to check the input and the empty
static method to create the empty object.
classdef MyClass methods function obj = subsasgn(obj,s,varargin) if isequal(obj,[]) obj = MyClass.empty; end obj = builtin('subsasgn',obj,s,varargin{:}); end end end
Subscripted assignment to an uninitialized variable now avoids the previous error.
clear B
B(1) = MyClass;
B = MyClass with no properties.