%% Customize Brace Indexing
% This example shows how to customize brace indexing in the ArrayofArrays class. ArrayOfArrays implements a 1-by-n array of arrays. The contained arrays can be of different classes, shapes, and sizes. The class inherits from both matlab.mixin.indexing.RedefinesBrace and matlab.mixin.indexing.RedefinesParen. The brace indexing customization handles references and assignments to the contained arrays:
% braceReference: Handles brace references into the Arrays property of the class. For example, the syntax instance{idx} accesses the contained array at index idx in Arrays.
% braceAssign: Handles brace assignments into the Arrays property. For example, the syntax instance{idx} = A assigns the value of A to the contained array at index idx in Arrays. If idx exceeds the current number of elements in Arrays, braceAssign creates the element and assigns A to it.
% braceListLength: Determines the number of values to return from brace indexing expressions that return a comma-separated list.
% ArrayOfArrays also inherits from RedefinesParen to support parentheses indexing in a way similar to cell arrays. For example, the syntax instance1(idx1) = instance2(idx2) assigns the contained array in instance2 at idx2 to idx1 in instance1. To see the full list of abstract methods that must be implemented when customizing parentheses indexing, see matlab.mixin.indexing.RedefinesParen.
% The class definition of ArrayOfArrays also includes two error-handling functions:
% ErrorForUnsupportedIndexing: Prevents any additional indexing after parentheses indexing in reference and assignment operations.
% ErrorForUnexpectedRightHandSide: Restricts parentheses assignments to cases when the right-hand side of the statement is an ArrayofArrays instance.
%% Code for ArrayOfArrays Class and Error-Handling Functions
% classdef ArrayOfArrays < matlab.mixin.indexing.RedefinesParen & ...
%         matlab.mixin.indexing.RedefinesBrace
%
%     properties (Access=private)
%         Arrays (1,:) cell
%     end
%
%     methods (Access=protected)
%         function varargout = braceReference(obj,indexOp)
%             [varargout{1:nargout}] = obj.Arrays.(indexOp);
%         end
%
%         function obj = braceAssign(obj,indexOp,varargin)
%             if isscalar(indexOp)
%                 [obj.Arrays.(indexOp)] = varargin{:};
%                 return;
%             end
%             [obj.Arrays.(indexOp)] = varargin{:};
%         end
%
%         function n = braceListLength(obj,indexOp,indexContext)
%             n = listLength(obj.Arrays,indexOp,indexContext);
%         end
%
%         function out = parenReference(obj,indexOp)
%             ErrorForUnsupportedIndexing(indexOp);
%             out = obj;
%             out.Arrays = obj.Arrays.(indexOp);
%         end
%
%         function obj = parenAssign(obj,indexOp,in)
%             ErrorForUnsupportedIndexing(indexOp);
%             ErrorForUnexpectedRightHandSide(in);
%             obj.Arrays.(indexOp) = in.Arrays;
%         end
%
%         function n = parenListLength(~,~,~)
%             n = 1;
%         end
%
%         function obj = parenDelete(obj,indexOp)
%             obj.Arrays.(indexOp) = [];
%         end
%     end
%
%     methods (Access=public)
%         function obj = ArrayOfArrays(varargin)
%             if nargin > 0
%                 obj.Arrays = varargin;
%             else
%                 obj.Arrays = [];
%             end
%         end
%
%         function out = cat(~,varargin)
%             out = ArrayOfArrays;
%             for ix = 1:length(varargin)
%                 tmp = varargin{ix};
%                 if isa(tmp,'ArrayOfArrays')
%                     out.Arrays = [out.Arrays,tmp.Arrays];
%                 else
%                     out.Arrays{end+1} = tmp;
%                 end
%             end
%         end
%
%         function varargout = size(obj,varargin)
%             [varargout{1:nargout}] = size(obj.Arrays,varargin{:});
%         end
%     end
%
%     methods (Static)
%         function out = empty()
%             out = ArrayOfArrays();
%         end
%     end
% end
%
% function ErrorForUnsupportedIndexing(indexOp)
%     if ~isscalar(indexOp)
%         error('Indexing after parentheses indexing is not supported.');
%     end
% end
%
% function ErrorForUnexpectedRightHandSide(val)
%     if ~isa(val,'ArrayOfArrays')
%         error(['Parentheses assignment is only supported when the ' ...
%             'right-hand side is an ArrayOfArrays.']);
%     end
% end
%
%
%% Use an ArrayOfArrays Instance
% Create an ArrayOfArrays instance with two contained arrays, a 2-element vector and a 3-by-3 matrix.

myArrays = ArrayOfArrays([1 2],2*eye(3));

%
% Use brace indexing to view the second contained array. The braceReference method accepts an IndexingOperation object that identifies what field to access.

myArrays{2}

%
% Use brace and parentheses indexing to extract the upper-right corner of the matrix in the second array. The class calls the braceReference method to access the contained array at index 2 and then forwards the parentheses indexing to the matrix itself.

myArrays{2}(1:2,2:3)

%
% Add a third element to the instance using brace assignment. The braceAssign method accepts an IndexingOperation object, which describes the type of indexing operation (Brace) and the indices referenced, and a second argument that contains the value to be assigned, in this case a cell array.  Verify the addition.

myArrays{3} = {1:5,6:10};
myArrays{3}

%
% Assign multiple new values to myArrays{3}. Because the assignment involves multiple values, MATLAB calls the braceListLength method to determine how many elements need to be assigned before calling braceAssign to handle the assignment operation.

[myArrays{3}{:}] = deal(5);
myArrays{3}

%
% The customized parentheses indexing implemented by the class enables parentheses references and assignment in a similar way to how this indexing works in cell arrays. Assign the contained arrays at indices 1 and 2 of myArrays to a new ArrayOfArrays instance, x. The class calls parenAssign to perform the operation. Use brace indexing to verify the contents of x.

x = myArrays(1:2);
x{1:2}

% Copyright 2020 The MathWorks, Inc.