Problem with subreferencing (subsref) operator overload

조회 수: 1 (최근 30일)
John
John 2014년 9월 2일
편집: Guillaume 2014년 9월 2일
I am experiencing a problem with operator overloading of the subreferencing operator for a class. Below is an illustrative MATLAB value class that has a property, x, that stores a vector of integers. Operator overloading for () is implemented by overloading the subsref function.
The documentation for subsref is here: http://www.mathworks.com/help/matlab/ref/subsref.html
classdef BizarreClass
properties
x;
end
methods
function obj = BizarreClass()
obj.x = [1 2 3 4 5];
end
function obj = setx(obj, x_val)
disp('called setx')
obj.x = x_val;
end
function varargout = subsref(obj, S)
%Ignore function calls and only tend to subreferences
if (strcmp(S(1).type, '()'))
disp('called for the right reason')
varargout{1} = obj.x(S(1).subs{1});
else
disp('called for the wrong reason')
varargout = {};
end
end
end
end
Now let's say I instantiate BizarreClass:
b = BizarreClass()
And then call the setx function to set x to a different value:
b = b.setx([1 3 5])
which gives an error:
Error in BizarreClass>BizarreClass.subsref (line 18)
if (strcmp(S(1).type, '()'))
Error using BizarreClass/subsref
Output argument "varargout" (and maybe others) not assigned during call to
"c:\users\johndoe\Desktop\swallowing\trunk\matlab_scripts\BizarreClass.m>BizarreClass.subsref".
This is happening because subsref is being called first (as it should). That is why I have logic that checks the input variable S and only handle the case where the object is subreferenced like b(3), in which case varargout gets the value indexed into the array, x. Otherwise, varargout is empty, which is the problem: The 'b = ' in 'b = setx([1 3 5])' needs to be there for the value of b to be updated. Unfortunately, this calls subsref first and not the setx method, causing that error.
I can get past this by calling setx on b like this:
b = setx(b, [1 3 5])
But I want to call it like:
b = b.setx([1 3 5])
Is there a solution? How do I not have subsref to be called for any case other than the subsref operator? Or is there a design pattern that I should use that will allow me to use b = b.setx([1 3 5])
  댓글 수: 1
John
John 2014년 9월 2일
I should add, it appears that when I call:
b.setx([1 3 5])
the subsref function is called but not the setx function even though subsref function returns.

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

답변 (1개)

Guillaume
Guillaume 2014년 9월 2일
편집: Guillaume 2014년 9월 2일
Unfortunately, once you overload subsref to handle (), you also have to handle . and {} in your overload:
b.method(...)
will only call subsref and not method anymore.
The simple thing to do is to error out in subsref when you S.type is '.' (or '{}') and output a message that dot notation is not supported (that's what matwhorks do in several of their classes, see the implementation of table for example) and use the function notation which always work as you found out.
The other option is to basically reimplement method calls from within subsref. The problem with that is because the call is within subsref it bypasses the access modifier (i.e. it then becomes possible to access private / protected methods) unless you also implement that within subsref. It's a can of worms.
Personally, I find the implementation of subsref completely broken (it should be 3 different functions) and instead of overloading (), I just implement a method GetAt that does what the overload would do. You loose the syntactic elegance of () but you also avoid a lot of pain.

카테고리

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

태그

Community Treasure Hunt

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

Start Hunting!

Translated by