How can I redefine indexing in my classes?

5 views (last 30 days)
I want to redefine indexing in my class definition for all three indexing types: parentheses, braces, and dot-indexing.I have seen examples where it is done by overloading "subsasgn", "subsref", and a series of other methods.
I have also seen threads that mention this approach has limitations, as linked below:
Examples of these limitations include: when overloading "numel", for fully managing {}-indexing, and for handling CSL-output with nested data structures.
Is there a better way to redefine indexing that addresses these issues?

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 1 Apr 2022
Edited: MathWorks Support Team on 1 Apr 2022
MATLAB allows class developers to redefine indexing methods for brace-, paren-, and dot-indexing. Prior to R2021b, this was done by overloading "subsasgn", "subsref", and a series of other methods. As mentioned above, this approach has limitations.
This problem can be solved more concisely by using modular indexing, a new paradigm for overloading indexing that was introduced in R2021b. The "MyCellModular" class attached to this answer is an example of a class that solves these issues. It overloads indexing by delegating array operations such as parentheses and brace indexing, "size", "numel", "end", and other array-like methods to a contained property.
By inheriting from the mixin classes "matlab.mixin.indexing.RedefinesBrace" and "matlab.mixin.indexing.RedefinesParen", the "MyCellModular" class signals to MATLAB that it will handle indexing expressions that begin with braces or parentheses. In this example, the class does not inherit from "matlab.mixin.indexing.RedefinesDot", so MATLAB will automatically handle indexing expressions that begin with dot according to the built-in rules for dot indexing.Note that modular indexing uses a new class, "matlab.indexing.IndexingOperation", in place of the substruct utilized by "subsref" and "subsasgn". Here are the documentation pages for those classes.
Modular indexing mixin classes:
"matlab.indexing.IndexingOperation" class:
As mentioned, one of the difficulties with "subsref" and "subsasgn" is delegating the remainder of an indexing expression to MATLAB. Specifically, with "subsref" and "subsasgn" we would have to introspect on what types of objects are in the "Array" property of a "MyCellModular" object so we could determine whether to call "builtin('subsref', …)" or "subsref(…)".Modular indexing solves this problem via a powerful functionality called forwarding:
Forwarding similarly delegates all remaining indexing operations to MATLAB, but it determines whether to call built-in indexing or overloaded indexing for us. This allows us to nest "MyCellModular" objects within several layers of containers without having to worry about whether those containers overload indexing. Here is the "braceReference" method of the "MyCellModular" class:
function varargout = braceReference(obj, indexOp)
[varargout{1:nargout}] = obj.Array.(indexOp);
end
The syntax "obj.Array.(indexOp)" tells MATLAB to apply the indexing operations described by "indexOp" to the data stored in the "Array" property.The "MyCellModular" class is an example of a class that overloads indexing by delegating array operations such as parentheses and brace indexing, "size", "numel", "end", and other array-like methods to a contained property. That is, instances of "MyCellModular" objects are scalars, but they appear to be arrays by overloading indexing operations and other array-like methods. Another advantage of using modular indexing is that the implementation of these array-like methods is provided by default in the "RedefinesParen" mixin.
For brevity, we have not implemented any of the paren indexing methods for the MyCellModular class.
You can experiment with modular indexing by downloading the file MyCellModular.m attached to this answer and by running the following example:
mcm1 = MyCellModular(1,2);
mcm2 = MyCellModular(2,3);
mcm1{1,1} = "John";
mcm1{1,2} = 38;
mcm2{1,1} = rand(2);
mcm2{2,1} = NaN;
mcm2{2,3} = mcm1;
This creates two "MyCellModular" objects, "mcm1" and "mcm2", fills them with test values, and saves "mcm1" into "mcm2". You can then check that indexing works properly:
mcm2{2,3}{2}
ans =
38
and that the issues mentioned in the question ("numel", nesting, CSL output) do not occur when using modular indexing:
numel(mcm2)
mcm2{2,3}{:}
[name,age] = mcm2{2,3}{:}
ans =
6
ans =
"John"
ans =
38
name =
"John"
age =
38
The interest of modular indexing is of course not to emulate MATLAB built-in cell arrays, but to show that you can implement your own indexing by redefining indexing methods. An example of a mapping class that redefines parentheses indexing and supports indexing with strings is provided in the documentation:
  2 Comments
xinyuan wu
xinyuan wu on 3 Mar 2022
quite annoying when distinguishing varieties of indexing types in 'subsasgn

Sign in to comment.

More Answers (0)

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!