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.
For an overview of object indexing, see Object Array Indexing.
MATLAB calls the subsref
and subsasgn
methods of your class with these arguments.
Method | Input | Output |
---|---|---|
|
|
|
|
|
|
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
.
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 reference
A 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.
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
— A char
vector with the
property name or cell array of the indices used in the expression, including
:
and end
.
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 indexing
S(2).subs
is set to a cell array containing the indices
{[1],[:]}
To overload the subsref
and subasgn
functions:
Determine the full indexing expression using the types
and
subs
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.
subsref
MethodThe following framework for the subsref
method shows how to use
information in the indexing structure in conditional statements. Your application can
involve other expression 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
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) 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