MATLAB: Passing arguments in classdef

classesindexingoop

I'm trying to understand the behavior of a class while passing arguments. The basic concept of a class is that it captures a data array along with information about the dimensions–so the sample class I have describes position and time information along with the data.
I began noticing this behavior when I started writing what I've referred to as "smart" indices for the data. So instead of calling the data field myIntensity.data and providing logical or numerical indices, I can call myIntensity.smartData and provide numbers or ranges that correspond to my position/time vectors within the class. I also want the user to be able to use MATLAB's normal indices with this smartData function, so my full class (skeleton below) also supports arguments like ':' and end.
The behavior I'm confused about is what happens when I use the 'end' argument. If I step through the smartData function, it will first catch on line 22 (if ~exist('x','var')), set my output value to all data, and return. However, it will then step into smartData a second time, except this time with the argument corresponding to 'end' set to the length of the corresponding dimension of the data I just returned. This is also true if not all input arguments are provided: e.g. if a previous argument is left out, the 'end' index argument will equal the length of the earlier dimension corresponding to its order in the arguments provided.
My question: why does MATLAB make a second function call? Does this reproduce on other machines/versions (mine: R2013b on 64-b Windows 7 Enterprise)? Can I rely on this behavior, or is it an artifact of my set-up and something I should warn the user about?
Sample code producing results described:
x = -5:5; y = 3.28:0.01:3.46; z = [0 2 6 8 10 12 16 18 20];
time = 0:0.1:20; data = zeros(length(x),length(y),length(z),length(time));
newIntensity = intensity(x,y,z,time,data);
myData = newIntensity.smartData(0,[3.3 3.35 3.4],[0 10 20],end);
-> myData returned corresponds to expected index, only after stepping through smartData function twice
classdef intensity
properties
x = [];
y = [];
z = [];
time = [];
data = [];
end
methods
% Initialize intensity object
function obj = intensity(x,y,z,time,data)
obj.x = x;
obj.y = y;
obj.z = z;
obj.time = time;
obj.data = data;
end
% smart indexing options
function val = smartData(obj,x,y,z,time)
if ~exist('x','var')
val = obj.data; % = [];
% If val = [] instead of obj.Data, then when smartData is called the second time
% around, the time index will be set to 1 instead of 201
% So the second time smartData is called, any indices originally set to 'end'
% are now set to length(dimension)
return;
end
xInds = obj.getSmartInds(obj.x(:),x(:));
yInds = obj.getSmartInds(obj.y(:),y(:));
zInds = obj.getSmartInds(obj.z(:),z(:));
timeInds = obj.getSmartInds(obj.time(:),time(:));
val = obj.data(xInds,yInds,zInds,timeInds);
end
end
methods (Access = private)
% getSmartInds differentiates between "smart" indices as those in
% range of the given list and "dumb" or "normal" indices as those
% not in range
function indsOut = getSmartInds(~,list,indsIn)
if all(indsIn >= min(list)) && all(indsIn <= max(list))
indsOut = dsearchn(list,indsIn);
else
indsOut = indsIn;
end
end
end
end
Thanks for your help.

Best Answer

This "feature" is undocumented behavior and I would consider it a bug subject to change in the future. All recent versions of MATLAB make both calls, the first call is made to (incorrectly?) get the size and hence the end of the property being indexed.
My gut instinct is that use of end on a method call should be an error in this instance. But should call the objects overloaded end function if it exists.
To completely customize indexing for your object look into documentation of the subsref and end methods.