필터 지우기
필터 지우기

Bug in subsref overloading

조회 수: 4 (최근 30일)
Paul
Paul 2016년 12월 8일
댓글: Paul 2016년 12월 13일
Let us first show expected behaviour:
classdef GoodDemo
properties
st;
end
methods
function obj = GoodDemo()
obj.st = struct('x', {1,2,3});
end
end
end
good = GoodDemo;
disp(good.st(2).x); % --> 2
disp({good.st.x}); % --> [1] [2] [3]
However, when we overload subsref (just let it return the built-in output, nothing fancy) things break:
classdef BugDemo
properties
st;
end
methods
function obj = BugDemo()
obj.st = struct('x', {1,2,3});
end
function varargout = subsref(obj, s)
[varargout{1:nargout}] = builtin('subsref', obj, s);
end
end
end
bug = BugDemo;
disp(bug.st(2).x); % --> 2
disp({bug.st.x}); % --> [1]
The problem seems to be that in the overloaded subsref somehow `nargout == 1`. Anything I am doing wrong here?
I found a bit of a crazy workaround, and the most problematic thing about it is it is only supported from 2015b onwards. The workaroud is to also overload the `numArgumentsFromSubscript` with -- big surprise -- its built-in value:
classdef WeirdFixDemo
properties
st;
end
methods
function obj = WeirdFixDemo()
obj.st = struct('x', {1,2,3});
end
function varargout = subsref(obj, s)
[varargout{1:nargout}] = builtin('subsref', obj, s);
end
function n = numArgumentsFromSubscript(obj, s, ic)
n = builtin('numArgumentsFromSubscript', obj, s, ic);
end
end
end
weird = WeirdFixDemo;
disp(weird.st(2).x); % --> 2
disp({weird.st.x}); % --> [1] [2] [3]
This works for Matlab 2015b+. Is there a way to get this working for earlier versions of Matlab? I tried setting `nargout` explicitly, but that has no effect at all.
  댓글 수: 9
per isakson
per isakson 2016년 12월 8일
"So I assume my bug report is "not publicly accessible" to you." &nbsp Your request will be processed. It will not be automatically included in the "bug-database". I believe that most issues are included, but that only an appropriate selection are on public display.
Walter Roberson
Walter Roberson 2016년 12월 8일
A more direct link to the report is https://www.mathworks.com/support/bugreports/555655

댓글을 달려면 로그인하십시오.

채택된 답변

David Foti
David Foti 2016년 12월 9일
Here is a little more explanation and possibly something that might help with the earlier MATLAB releases. The numel function was originally introduced before 2000 as a means of telling MATLAB how many elements to expect or request from an overloaded subsref using dot and a field or property name. It was given a default implementation that returned the number of elements in the array being subscripted. This worked for object arrays that wanted to return one array for each element in the object array. If the class wanted to emulate a numeric array using a scalar object but have fields that applied to the whole array, it could overload numel to return 1. This solution didn't always work well for more complicated forms of indexing or for what some people wanted to do with brace or cell indexing. That led to the new design that provides more information and allows the class to handle more kinds of indexing correctly.
Another motivation for the new function was the fact that numel was such a nice simple name for getting the number of elements in an array that it started getting used as a better alternative to prod(size(X)) as a way to get the total number of elements in arrays. However, classes that needed to overload numel to return 1 for subref didn't return the right value for the total number of array elements.
I don't know what your actual class needs in terms of subscripting (I assume the example is heavily simplified), but if you want something similar to what you have in your example and can live with numel not returning the true number of elements in your array, then you could overload numel to return the number of elements in st rather than the number of elements in obj. It would look something like:
classdef NumelFixDemo
properties
st;
end
methods
function obj = NumelFixDemo()
obj.st = struct('x', {1,2,3});
end
function varargout = subsref(obj, s)
[varargout{1:nargout}] = builtin('subsref', obj, s);
end
function n = numel(obj)
n = numel(obj.st);
end
end
end
  댓글 수: 1
Paul
Paul 2016년 12월 13일
It feels a bit strange to use this workaround because I overloaded `size` to return the size of another attribute than for which I am now overloading `numel`, but based on a few tests I think this could more or less work. At least the gained functionality certainly justifies the hack. Thanks very much for the explanation too.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Philip Borghesani
Philip Borghesani 2016년 12월 8일
I don't think there is anything new here or any new bugs here. There was a design flaw with how numel was used to implement the number of outputs from subsref in a comma separated list context, that was fixed by adding the function numArgumentsFromSubscript in R2015b. There is no way to get your desired output in previous versions of MATLAB.
To maintain compatibility with existing classes that implemented subsref, numArgumentsFromSubscript is only used when it is implemented by a class if the class implements subsref. The builtin returns the number of outputs that would be expected from the indexing operation passed as inputs provided there was no subsref function.
  댓글 수: 1
Paul
Paul 2016년 12월 9일
편집: per isakson 2016년 12월 9일
OK. So the element of surprise was designed.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Logical에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by