Quantcast

Documentation Center

  • Trial Software
  • Product Updates

Indexed Reference and Assignment

Overview

This section describes how indexed reference and assignment work in MATLAB®, and provides information on the behaviors you can modify. There are also examples of classes that modify the default indexing behavior.

MATLAB provides support for object array indexing by default and many class designs will require no modification to this behavior. The information in this section can help you determine if modifying object indexing is useful for your class design and can show you how to approach those modifications.

Default Indexed Reference and Assignment

MATLAB arrays enable you to reference and assign elements of the array using a subscripted notation that specifies the indices of specific array elements. For example, suppose you create two arrays of numbers (using randi and concatenation).

% Create a 3-by-4 array of integers between 1 and 9
A = randi(9,3,4)

A =

     4     8     5     7
     4     2     6     3
     7     5     7     7
% Create a 1-by-3 array of the numbers 3, 6, 9
B = [3 6 9];

You can reference and assign elements of either array using index values in parentheses:

B(2) = A(3,4);
B
B =
     3     7     9

When you execute a statement that involves indexed reference:

C = A(3,4);

MATLAB calls the built-in subsref function to determine how to interpret the statement. Similarly, if you execute a statement that involves indexed assignment:

C(4) = 7;

MATLAB calls the built-in subsasgn function to determine how to interpret the statement.

The MATLAB default subsref and subsasgn functions also work with user-defined objects. For example, suppose you want to create an array of objects of the same class:

for k=1:3
   objArray(k) = MyClass;
end

Referencing the second element in the object array, objArray, returns the object constructed when k = 2:

D = objArray(2);
class(D)

ans =

MyClass

You also can assign an object to an array of objects of the same class, or an uninitialized variable (see Creating Empty Arrays for related information):

newArray(3,4) = D;

Arrays of objects behave much like numeric arrays in MATLAB. You do not need to implement any special methods to provide this behavior with your class.

For general information about array indexing, see Matrix Indexing.

What You Can Modify

You can modify your class's default indexed reference and/or assignment behavior by implementing class methods called subsref and subsasgn. For syntax description, see their respective reference pages. Keep in mind that once you add a subsref or subsasgn method to your class, then MATLAB calls only the class method, not the built-in function. Therefore, you must implement in your class method all of the indexed reference and assignment operations that you want your class to support. This includes:

  • Dot notation calls to class methods

  • Dot notation reference and assignment involving properties

  • Any indexing using parentheses '()'

  • Any indexing using braces '{}'

While implementing subsref and subsasgn methods gives you complete control over the interpretation of indexing expressions for objects of your class, it can be complicated to provide the same behavior that MATLAB provides by default.

When to Modify Indexing Behavior

The default indexing supported by MATLAB for object arrays and dot notation for access to properties and methods enables user-defined objects to behave like intrinsic classes, such as double and struct. For example, suppose you define a class with a property called Data that contains an array of numeric data. A statement like:

obj.Data(2,3)

returns the value contained in the second row, third column of the array. If you have an array of objects, you can use an expression like:

objArray(3).Data(4:end)

to return the fourth through last elements in the array contained in the Data property of the third object in the object array, objArray.

Modify the default indexing behavior when your class design requires behavior that is different from that provided by MATLAB by default.

subsref and subsasgn Within Class Methods — Built-In Called

MATLAB does not call class-defined subsref or subsasgn methods for indexed reference and assignment within the class's own methods. Within class methods, MATLAB always calls the built-in subsref and subsasgn functions regardless of whether the class defines its own methods. This is true within the class-defined subsref and subsasgn methods as well.

For example, within a class method, this dot reference:

% Calls built-in subsref
obj.Prop

calls the built-in subsref function. To call the class-defined subsref method, use:

% Calls overloaded subsref
subsref(obj,substruct('.','Prop'))

Whenever a class method requires the functionality of the class-defined subsref or subsasgn method, it must call the overloaded methods with function calls rather than using the operators, '()', '{}', or '.'.

For example, suppose you define a polynomial class with a subsref method that causes the polynomial to be evaluated with the value of the independent variable equal to the subscript. This statement defines the polynomial with its coefficients:

p = polynom([1 0 -2 -5]);

The MATLAB expression for the resulting polynomial is:

x^3 - 2*x - 5

The following subscripted expression returns the value of the polynomial at x = 3:

p(3)
ans =
    16

Suppose that you want to use this feature in another class method. To do so, call the subsref function directly. The evalEqual method accepts two polynom objects and a value at which to evaluate the polynomials:

methods
   function ToF = evalEqual(p1,p2,x)
      % Create arguments for subsref
      subs.type = '()';
      subs.subs = {x};
      % Need to call subsref explicity 
      y1 = subsref(p1,subs);
      y2 = subsref(p2,subs);
      if y1 == y2
         ToF = true;
      else 
         ToF = false;
      end
   end
end

This behavior enables you to use standard MATLAB indexing to implement specialized behaviors. See A Class with Modified Indexing for examples of how to use both built-in and class-modified indexing.

Understanding Indexed Reference

Object indexed references are in three forms — parentheses, braces, and name:

A(I)
A{I}
A.name

Each of these statements causes a call by MATLAB to the subsref method of the class of A, or a call to the built-in subsref function, if the class of A does not implement a subsref method.

MATLAB passes two arguments to subsref:

B = subsref(A,S)

The first argument is the object being referenced, A. The second argument, S, is a struct array with two fields:

  • S.type is a string containing '()', '{}', or '.' specifying the indexing type used.

  • S.subs is a cell array or string containing the actual index or name. A colon used as an index is passed in the cell array as the string ':'. Ranges specified using a colon (e.g., 2:5) are expanded to 2 3 4 5.

For example, the expression

A(1:4,:)

causes MATLAB to call subsref(A,S), where S is a 1-by-1 structure with

S.type = '()'
S.subs = {1:4,':'} % A 2-element cell array 
                   % containing the numbers 1 2 3 4 and ":"

Returning the contents of each cell of S.subs gives the index values for the first dimension and a string ':' for the second dimension:

S.subs{:}
ans =

     1     2     3     4

ans =

:

The default subsref returns all array elements in rows 1 through 4 and all of the columns in the array.

Similarly, the expression

A{1:4}

uses

S.type ='{}'
S.subs = {1:4} % A cell array
               % containing the numbers 1 2 3 4

The default subsref returns the contents of all cell array elements in rows 1 through 4 and all of the columns in the array.

The expression

A.Name

calls subsref(A,S) where

S.type = '.'
S.subs = 'Name' % The string 'Name'

The default subsref returns the contents of the Name field in the struct array or the value of the property Name if A is an object with the specified property name.

Complex Indexed References

These simple calls are combined for more complicated indexing expressions. In such cases, length(S) is the number of indexing levels. For example,

A(1,2).PropertyName(1:4)

calls subsref(A,S), where S is a 3-by-1 structure array with the values:

S(1).type = '()'    S(2).type = '.'              S(3).type = '()'
S(1).subs = {1,2}   S(2).subs = 'PropertyName'   S(3).subs = {1:4}

Writing subsref

Your class's subsref method must interpret the indexing expressions passed in by MATLAB. Any behavior you want your class to support must be implemented by your subsref. However, your method can call the built-in subsref to handle indexing types that you do not want to change.

You can use a switch statement to determine the type of indexing used and to obtain the actual indices. The following three code fragments illustrate how to interpret the input arguments. In each case, the function must return the value (B) that is returned by your subsref function.

For a parentheses index:

% Handle A(n)
switch S.type
case '()'
   B = A(S.subs{:});
end

For a brace index:

% Handle A{n}
switch S.type
case '{}'
% Determine what this indexing means to your class
% E.g., CellProperty contained a cell array
   B = A.CellProperty{S.subs{:}}; 
end

While braces are used for cell arrays in MATLAB, your subsref method is free to define its own meaning for this syntax.

For a name index, you might access property values. Method calls require a second level of indexing if there are arguments. The name can be an arbitrary string for which you take an arbitrary action:

switch S.type
case '.'
   switch S.subs
   case 'name1'
      B = A.name1;
   case 'name2'
      B = A.name2;
   end
end

Examples of subsref

These links show examples of classes that implement subsref methods:

A Class with Modified Indexing

Subclasses of Built-In Types with Properties

A Class to Represent Hardware

The DocPolynom subsref Method

See also, Understanding size and numel

Avoid Overriding Access Attributes

Because subsref is a class method, it has access to private class members. Avoid inadvertently giving access to private methods and properties as you handle various types of reference. Consider this subsref method defined for a class having private properties, x and y:

classdef MyPlot
   properties (Access = private)
      x
      y
   end
   properties
      Maximum
      Minimum
      Average
   end
   methods 
      function obj = MyPlot(x,y)
         obj.x = x;
         obj.y = y;
         obj.Maximum = max(y);
         obj.Minimum = min(y);
         obj.Average = mean(y);
      end
      function B = subsref(A,S)
         switch S(1).type
            case '.'
               switch S(1).subs
                  case 'plot' 
                     % Reference to A.x and A.y call built-in subsref
                     B = plot(A.x,A.y); 
                  otherwise
                     % Enable dot notation for all properties and methods
                     B = A.(S.subs); 
               end
         end
      end
   end
end

This subsref enables users to use dot notation to perform an action (create a plot) using the name 'plot'. The statement:

obj = MyPlot(1:10,1:10);
h = obj.plot;

calls the plot function and returns the handle to the graphics object.

You do not need to explicitly code each method and property name because the otherwise code in the inner switch block handles any name reference that you do not explicitly specify in case statements. However, using this technique exposes any private and protected class members via dot notation. For example, you can reference the private property, x, with this statement:

obj.x

ans =

     1     2     3     4     5     6     7     8     9    10

The same issue applies to writing a subsasgn method that enables assignment to private or protected properties. Your subsref and subsasgn methods might need to code each specific property and method name explicitly to avoid violating the class design.

Understanding Indexed Assignment

Object indexed assignments are in three forms — parentheses, braces, and name:

A(I) = B
A{I} = B
A.name = B

Each of these statements causes a call by MATLAB to the subsasgn method of the class of A, or a call to the built-in function, if the class of A does not implement a subsasgn method.

MATLAB passes three arguments to subsasgn:

A = subsasgn(A,S,B)

The first argument, A, is the object being assigned the value in the third argument B.

The second argument, S, is a struct array with two fields:

  • S.type is a string containing '()', '{}', or '.' specifying the indexing type used.

  • S.subs is a cell array or string containing the actual index or name. A colon used as an index is passed in the cell array as the string ':'. Ranges specified using a colon (e.g., 2:5) are expanded to 2 3 4 5.

For example, the assignment statement:

A(2,3) = B;

generates a call to subsasgn: A = subsasgn(A,S,B) where S is:

S.type = '()'
S.subs = {2,3}

The default subsasgn:

  • Determines the class of A. If B is not the same class a A, then MATLAB tries to construct an object of the same class as A using B as an input argument (e.g., by calling a converter method, if one exists). If this attempt fails, MATLAB returns an error.

  • If A and B are, or can be made, into the same class, then MATLAB assigns the value of B to the array element at row 2, column 3.

  • If A does not exist before you execute the assignment statement, then MATLAB initializes the five array elements that come before A(2,3) with a default object of the class of A and B. For example, empty elements are initialized to zero in the case of a numeric array or an empty cell ([]) in the case of cell arrays. See Creating Empty Arrays for more information on how MATLAB initializes empty arrays.

Similarly, the expression

A{2,3} = B

uses

S.type ='{}'
S.subs = {2,3} % A 2-element cell array containing the numbers 2 and 3

The default subsasgn:

  • Assigns B to the cell array element at row 2, column 3.

  • If A does not exist before you execute the assignment statement, MATLAB initializes the five cells that come before A(2,3) with []. The result is a 2–by3 cell array.

The expression

A.Name = B

calls A = subsasgn(A,S,B) where

S.type = '.'
S.subs = 'Name' % The string 'Name'

The default subsasgn:

  • Assigns B to the struct field Name.

  • If A does not exist before you execute the assignment statement, MATLAB creates a new struct variable, A with field Name and assigns the value of B to this field location.

  • If struct A exists, but has no field Name, then MATLAB adds the field Name and assigns the value of B to the new field location.

  • If struct A exists and has a Name field, then MATLAB assigns the value of B to Name.

You can redefine all or some of these assignment behaviors by implementing a subsasgn method for your class.

Indexed Assignment to Objects

If A is an object, the expression:

A.Name = B

calls A = subsasgn(A,S,B) where

S.type = '.'
S.subs = 'Name' % The string 'Name'

The default subsasgn:

  • Attempts to assign B to the Name property.

  • If the class of A does not have a Name property, MATLAB returns an error.

  • If the Name property has restricted access (private or protected), MATLAB determines if the assignment is allowed based on the context in which the assignment is made.

  • If the class of A defines a set method for property Name, MATLAB calls the set method.

  • MATLAB applies all other property attributes before determining whether to assigning B to the property Name.

Complex Indexed Assignments

These simple calls are combined for more complicated indexing expressions. In such cases, length(S) is the number of indexing levels. For example,

A(1,2).PropertyName(1:4) = B

calls subsasgn(A,S,B), where S is a 3-by-1 structure array with the values:

S(1).type = '()'    S(2).type = '.'              S(3).type = '()'
S(1).subs = {1,2}   S(2).subs = 'PropertyName'   S(3).subs = {1:4}

For an example of subsasgn method, see Specialized Subscripted Assignment — subsasgn.

A Class with Modified Indexing

This example defines a class that modifies the default indexing behavior. It uses a combination of default indexing and specialized indexing. The example shows some useful techniques for implement subsref and subsasgn methods, but does not implement a fully robust class. You cannot, for example, concatenate objects into an array without adding other methods, such as horzcat, vertcat, cat, size, and perhaps other methods.

See Subclasses of Built-In Types with Properties for another example of a class that modifies indexing and concatenation behavior.

Class Description

The class has three properties:

  • Data — numeric test data

  • Description — description of test data

  • Date — date test was conducted

Assume you have the following data (randi):

d = randi(9,3,4)
d =

     8     9     3     9
     9     6     5     2
     2     1     9     9

Create an instance of the class:

obj = MyDataClass(d,'Test001');

The constructor arguments pass the values for the Data and Description properties. The clock function assigns the value to the Date property from within the constructor. This approach captures the time and date information when the instance is created.

Here is the basic code listing without the subsref and subsasgn methods.

classdef MyDataClass
   properties
      Data
      Description
   end
   properties (SetAccess = private)
      Date
   end
   methods
      function obj = MyDataClass(data,desc)
         if nargin > 0
            obj.Data = data;
         end
         if nargin > 1
            obj.Description = desc;
         end
         obj.Date = clock; 
      end
   end
end

Specialized Subscripted Reference — subsref

Use the default indexed reference behavior for scalar objects, and add the ability to index into the Data property with an expression like:

obj(2,3)

ans =

     5

This statement is the equivalent of:

obj.Data(2,3)

which the class also supports.

Redefining '()' indexing as described here means you cannot create arrays of MyDataClass objects and use '()' indexing to access individual objects. Create only scalar objects.

To achieve the design goals, the subsref method calls the builtin subsref for indexing of type '.' and defines its own version of '()' type indexing.

function sref = subsref(obj,s)
% obj(i) is equivalent to obj.Data(i)
   switch s(1).type
      % Use the built-in subsref for dot notation
      case '.'
         sref = builtin('subsref',obj,s);
      case '()'
         if length(s)<2
         % Note that obj.Data is passed to subsref
            sref = builtin('subsref',obj.Data,s);
            return
         else
            sref = builtin('subsref',obj,s);
         end
      % No support for indexing using '{}'
      case '{}'
         error('MYDataClass:subsref',...
           'Not a supported subscripted reference')
   end 
end

Specialized Subscripted Assignment — subsasgn

The class supports the equivalent behavior in indexed assignment. You can assign values to the Data property by referencing only the object.

obj(2,3) = 9;

is equivalent to:

obj.Data(2,3) = 9;

Like the subsref method, the subsasgn method calls the builtin subsasgn for indexing of type '.' and defines its own version of '()' type indexing.

Another useful approach is the use of the substruct function to redefine the index type and index subscripts struct that MATLAB passes to subsref and subsasgn.

function obj = subsasgn(obj,s,val)
   if isempty(s) && strcmp(class(val),'MYDataClass')
      obj = MyDataClass(val.Data,val.Description);
   end
   switch s(1).type
   % Use the built-in subsasagn for dot notation
      case '.'
         obj = builtin('subsasgn',obj,s,val);
      case '()'
         if length(s)<2
            if strcmp(class(val),'MYDataClass')
               error('MYDataClass:subsasgn',...
                    'Object must be scalar')
            elseif strcmp(class(val),'double')
            % Redefine the struct s to make the call: obj.Data(i)
               snew = substruct('.','Data','()',s(1).subs(:));
                     obj = subsasgn(obj,snew,val);
            end
         end
      % No support for indexing using '{}'
      case '{}'
         error('MYDataClass:subsasgn',...
            'Not a supported subscripted assignment')
   end     
end

Implementing Addition for Object Data — plus

Allow direct addition of the Data property data by implementing a plus method:

function a = double(obj)
   a = obj.Data;
end
      
function c = plus(obj,b)
   c = double(obj) + double(b);
end

For example, add a scalar to the object Data array:

% List Current value of Data
obj(:,:) 

ans =

     8     9     3     9
     9     6     5     2
     2     1     9     9

% Add 7 to the array
obj + 7

ans =

    15    16    10    16
    16    13    12     9
     9     8    16    16

The MyDataClass double method provides a way to convert an object to an array of doubles. It is possible to add a MyDataClass object to another class of object, providing the other class implements a double method that also returns an array of doubles. MATLAB applies the rules of addition and returns errors for dimension mismatch, and so on.

Defining end Indexing for an Object

When you use end in an object indexing expression, such as A(4:end), the end function returns the index value corresponding to the last element in that dimension.

Classes can overload the end function as a class method to implement specialized behavior. If your class defines an end method, MATLAB calls that method to determine how to interpret the expression.

The end has the calling syntax:

ind = end(A,k,n)

where

  • A is the object

  • k is the index in the expression using the end syntax

  • n is the total number of indices in the expression

  • ind is the index value to use in the expression

For example, consider the expression

A(end-1,:)

MATLAB calls the end method defined for the object A using the arguments

ind = end(A,1,2)

These arguments mean the end statement occurs in the first index element and there are two index elements. The end class method returns the index value for the last element of the first dimension (from which 1 is subtracted in this case). If your class implements an end method, ensure that it returns a value appropriate for the class.

The end Method for the MyDataClass Example

The end method for the MyDataClass example (see A Class with Modified Indexing) operates on the contents of the Data property. The objective of this method is to return a value that can replace end in any indexing expression, such as:

obj(4:end)
obj.Data(2,3:end)

and so on.

The following end function determines a positive integer value for end and returns it so that MATLAB can plug it into the indexing expression.

function ind = end(obj,k,n)
   szd = size(obj.Data);
   if k < n
      ind = szd(k);
   else
      ind = prod(szd(k:end));
   end
end

Using Objects as Indices

MATLAB can use objects as indices in indexed expressions. The rules of array indexing apply — indices must be positive integers. Therefore, MATLAB must be able to derive a value from the object that is a positive integer, which it uses in the indexed expression.

Indexing expressions like X(A), where A is an object, cause MATLAB to call the default subsindex function, unless such an expression results in a call to an overloaded subsref or subsasgn method defined by the class of X. See Scenarios for Implementing Objects as Indices.

subsindex must return the value of the object as a zero-based integer index values in the range 0 to prod(size(X))-1).

Scenarios for Implementing Objects as Indices

If you want to enable indexing of one object by another object, such as X(A), you can implement this behavior in various ways:

  • Define a subsindex method in the class of A, which converts A to an integer. MATLAB calls A's subsindex method to perform default indexing operations (when the class of X does not overload the default subsref or subsasgn method).

  • If the class of X overloads subsref or subsasgn, these methods can explicitly call the subsindex method of A. In this case, ensure that A implements a subsindex method with appropriate error checking in your program.

  • If the class of X overloads subsref or subsasgn, these methods can contain code that determines an integer index value without relying on the class of A to implement a subsindex method.

Implementing subsindex

MATLAB calls the subsindex method defined for the object used as the index. For example, suppose you want to use object A to index into object B. B can be a single object or an array, depending on your objectives.

C = B(A);

A subsindex method implemented by class A might do something as simple as convert the object to double format to be used as an index, as shown in this sample code.

function ind = subsindex(obj)
% Convert the object a to double format to be used
% as an index in an indexing expression
   ind = double(obj);
end

Or, your class might implement a special converter method that returns a numeric value representing an object based on particular values of object properties.

function ind = subsindex(obj)
% Return the value of an object property
   ind = obj.ElementPosition;
end

subsindex values are 0-based, not 1-based.

Was this topic helpful?