Why do I receive errors when overloading SUBSREF for types {} and . for MATLAB classes?

4 views (last 30 days)
I also receive errors when I try to index into a user-defined object using curly braces {} and the index is something other than a double. My code used to work in MATLAB 6.0 (R12), but it does not work for later releases.
Typical errors might look like these:
ERROR: ??? Error using ==> myclass/subsref
Too many output arguments.
??? Error using ==> subsref
Too many output arguments.
??? Error using ==> numel
Bad subscripting index.

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 21 Oct 2021
Edited: MathWorks Support Team on 17 Feb 2021
=========Update for R2015b and later=======
In order to handle the possibility of a comma separated list of output arguments when indexing with curly braces '{}' or dot notation '.', MATLAB calls numArgumentsFromSubscript to determine the number of output arguments from the size of the input indices. If your class design requires that indexing operations return or assign a different number of values than the number defined by the indexing operation, overload numArgumentsFromSubscript  to specify the required number instead of numel as is suggested for R2015a and prior releases below. Since numel is also called implicitly, it is better to overload numArgumentsFromSubscript to control the results from overloaded subsref or subsasgn. When a class overloads numArgumentsFromSubscript, MATLAB calls this method instead of numel to compute the number of arguments expected for subsref nargout and subsasgn nargin. For more details, refer to this documentation on modifying nargout and nargin for Indexing methods.
If classes do not overload numArgumentsFromSubscript, MATLAB calls numel to compute the values of nargout or nargin. Another thing to note is that before MATLAB release R2015b, MATLAB incorrectly computed the number of arguments expected for outputs from subsref and inputs to subsasgn for some indexing expressions that return or assign to a comma-separated list. With release R2015b, MATLAB correctly computes the values of nargout and nargin according to the number of arguments required by the indexing expression.
=========
Behavior for R2015a and prior releases
=======
As of MATLAB 6.1 (R12.1), the function NUMEL was added to enhance the power of MATLAB object oriented programming. In short, the function allows you to index into objects with an arbitrary length vector, and return an arbitrary number of output arguments.
In MATLAB 6.0 (R12) and previous version, MATLAB called SIZE to figure out the number of output arguments. However, as users wanted to overload the SIZE function for their classes, they were not able to retain both uses of the function. Therefore, NUMEL was introduced.
The addition of this function came at the expense of breaking backward compatibility of a specific type of code that we did not expect customers to be writing. In this code, if you have not appropriately overloaded NUMEL for your class, then in some cases you will receive an error. The following is a more detailed description of the problem, including a resolution, and a recommended way to work around the problem:
When indexing into an object using curly braces or a dot ( {} or . ), you are introducing the possibility of returning a comma separated list of output arguments. This is done by design in MATLAB. See the Related Solution for more information (including some information about MATLAB classes).
In these cases (curly braces and dot indexing), MATLAB makes a call to NUMEL, which uses the size of the input index to determine the number of output arguments. For example, the following code will return a comma separated list of output:
myordinalvar = {'first','second','third','fourth','fifth','sixth','seventh','eighth','ninth','tenth'};
% In the following code, NUMEL of the index returns 3
ne = numel([6:8])
myordinalvar{6:8}
ne =
3
ans =
sixth
ans =
seventh
ans =
eigth
However, if you want to create an "ordinals" class that will behave differently than the example above, you can design it such that indexing into it with curly braces returns a character array designating the ordinal range. For example, if you index into it with [6:8], you will return the character array 'sixth, seventh, eighth'. In this case, the length of the index vector (3) does not match the number of outputs (1).
Therefore, to allow curly brace indexing into your object while returning a number of arguments INCONSISTENT with the size of the input, you will need to overload the NUMEL function inside your class directory.
In the case of this "ordinals" object example above, for a multiple input index and a single desired output, the following implementation of NUMEL will solve the problem:
function n = numel(varargin)
n = 1;
The functions might look like this:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function obj = ordinals
obj.ordinalstrs = {'first','second','third','fourth','fifth','sixth','seventh','eighth','ninth','tenth'};
obj = class(obj,'ordinals');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = subsref(m,s)
switch s(1).type
% when indexing with curly braces...
case '{}'
str = '';
% add each ordinal string
for n=[s(1).subs{1}]
str = [str m.ordinalstrs{n} ', '];
end
% remove the trailing ", "
str(end-1:end)=[];
varargout{1} = str;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function n = numel(varargin)
% Tell object to return one argument
n = 1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The implementation might look like this:
myordinalobj = ordinals;
ordstr = myordinalobj{6:8}
ordstr =
sixth, seventh, eighth
Overloading NUMEL can also be required when you are using a character array index inside curly braces, and you want a single output argument. The reason for this is that a string is several characters long, and represented by a vector of the same length.
numel('several characters')
ans =
18
MATLAB thinks you want to return an argument for each character, since you are indexing into a cell array. For example, you need to overload NUMEL to return 1 argument if you were performing an index operation such as:
mypersonobj{'name'}
ans =
Penelope
However, for additional desired behavior, the implementation will require that you pay close attention to the design of your SUBSREF and NUMEL functions.
NOTE: If you are designing your class to output only one argument, it is not recommended that you use curly brace indexing that requires you to overload NUMEL. Instead, it is recommended you use smooth brace () indexing. The above examples ignore the recommendation so that they could guide you in working around any possible backward compatibility problems you may have encountered.
To follow the recommendation, consider the following substitution code for the "ordinals" class. Notice how NUMEL does not need to be overloaded, since the implementation can now index with smooth braces as opposed to curly:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function obj = ordinals
obj.ordinalstrs = {'first','second','third','fourth','fifth','sixth','seventh','eighth','ninth','tenth'};
obj = class(obj,'ordinals');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = subsref(m,s)
switch s(1).type
% when indexing with curly braces...
case '()'
str = '';
% add each ordinal string
for n=[s(1).subs{1}]
str = [str m.ordinalstrs{n} ', '];
end
% remove the trailing ", "
str(end-1:end)=[];
varargout{1} = str;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
The implementation would look like this:
myordinalobj = ordinals;
ordstr = myordinalobj(6:8)
For more information on MATLAB OOPS, see the following online documentation:
Click on the "MATLAB Classes and Objects" link in the right hand frame.
For more information on SUBSREF, SUBSASGN, and NUMEL, refer to the documentation by entering the following at the MATLAB prompt:
doc subsref
doc subsasgn
doc numel

More Answers (0)

Categories

Find more on Matrices and Arrays in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!