Why can't I use builtin for classes that overload subsref?

It seems like Matlab's 'builtin' function doesn't work when subsref is overloaded in a class. Consider this class:
classdef TestBuiltIn
properties
testprop = 'This is the built in method';
end
methods
function v = subsref(this, s)
disp('This is the overloaded method');
end
end
end
To use the overloaded subsref method, I do this:
t = TestBuiltIn;
t.testprop
>> This is the overloaded method
That's as expected. But now I want to call Matlab's built in subsref method. To make sure I'm doing things right, first I try out a similar call on a struct:
x.testprop = 'Accessed correctly';
s.type = '.';
s.subs = 'testprop';
builtin('subsref', x, s)
>> Accessed correctly
That's as expected as well. But, when I try the same method on TestBuiltIn:
builtin('subsref', t, s)
>> This is the overloaded method
...Matlab calls the overloaded method rather than the built in method. Why does Matlab call the overloaded method when I requested that it call the builtin method?

 Accepted Answer

Matt J
Matt J on 24 Apr 2013
Edited: Matt J on 24 Apr 2013
I'm guessing a bit, but in MATLAB there are certain precedence rules for choosing which versions of functions can apply to a given list of input arguments. I think BUILTIN can only choose between functions that are of equal precedence (other than w.r.t. position on the path, of course).
In your case, you are calling builtin('subsref',...) with an object, t, of a user-defined class testBuiltIn, as an input argument. Under the precedence rules, user-defined class methods dominate everything but subfunctions, so the only versions of subsref that are of equal precedence are those belonging to the TestBuiltIn class. MATLAB's builtin subsref is not a method of TestBuiltIn, so it is ignored by builtin('subsref',t,s).
It might be worth talking to Tech Support to see if this is intended behavior.

6 Comments

So basically, it is impossible to invoke Matlab's built in subsref function on a class that overloads subsref from outside that class's overloaded subsref method?
Separately, it seems that Matlab's built in subsref function for a class that overloads subsref CAN be invoked from inside the overloaded subsref method. So basically that means it is impossible to write a generalized subsref handler function that behaves like the normal Matlab subsref. So, whenever someone wants to override the behavior of indexing into a class with (), they must also re-implement Matlab's {} and . indexing from scratch for each class.
So basically, it is impossible to invoke Matlab's built in subsref function on a class that overloads subsref from outside that class's overloaded subsref method?
No, the thing you call "MATLAB's built in subsref function" is automatically and always invoked by indexing operations on class objects inside the class' methods. That's true of all class methods, be it subsref or otherwise. It's also true whether the operation is done through BUILTIN or through explicit indexing expressions. It's only indexing operations executed outside the class that invoke the class' subsref.
It is impossible, I guess, to revert to built-in subsref behavior outside the class using BUILTIN, but I'm not sure why you would want to. The primary purpose of builtin('subsref',...) is to overload subsref for a class. I can't see when you would want to use it outside of a user-defined subsref, let alone outside the class.
So, whenever someone wants to override the behavior of indexing into a class with (), they must also re-implement Matlab's {} and . indexing from scratch for each class.
Once you declare a subsref method for the class, you have to implement any form of indexing you intend to use. However, BUILTIN works as you want it to inside the class' subsref, so I'm not sure what problem you see with that.
the thing you call "MATLAB's built in subsref function" can be invoked from within any method of the class, not only subsref
No, that's wrong. Consider this class:
classdef SubsrefInClass
properties
testprop = 'This is the built in method';
end
methods
function v = subsref(this, s)
v = 'This is the overloaded method';
end
function v = test1(this)
s.type = '.';
s.subs = 'testprop';
v = builtin('subsref', this, s);
end
function v = test2(this)
v = this.testprop;
end
end
end
Both test1 and test2 return 'This is the overloaded method'.
Once you declare a subsref method for the class, you have to implement any form of indexing you intend to use. However, BUILTIN works as you want it to inside the class' subsref, so I'm not sure what problem you see with that.
Well sorta; here's the problem. Say I want to override just () referencing like Matlab's griddedInterpolant class does. I write this class:
classdef TestIndexing
properties
prop1 = 123;
child
end
methods
function this = TestBuiltIn(n)
if nargin==0
n = 1;
end
if n<2
this.child = TestBuiltIn(n+1);
else
this.child = ['child on instance ' num2str(n)];
end
end
function v = subsref(this, s)
v = this;
if strcmp(s(1).type, '()')
v = 'overloaded method';
s = s(2:end);
end
if ~isempty(s)
v = builtin('subsref', this, s);
end
end
end
end
Now I make an instance and see that the overloaded subsref works:
t = TestIndexing;
t.prop1
>> 123
t(1)
>> overloaded method
The problem is that subsref doesn't actually work like before. Consider this:
tc = t.child;
tc(1)
>> overloaded method
t.child(1)
>> [returns TestIndexing instance]
This is undesirable; the desired behavior is what happens if child is a struct member:
x.child = t.child;
x.child(1)
>> overloaded method
Both test1 and test2 return 'This is the overloaded method'.
Nope. This is what I get,
>> test1(t)
ans =
This is the built in method
>> test2(t)
ans =
This is the built in method
I'm guessing that you used the following syntax instead, but these expressions do not genuinely invoke test1() and test2().
>> t.test1
ans =
This is the overloaded method
>> t.test2
ans =
This is the overloaded method
Again, because you executed these expressions outside the class, they were never interpreted as calls to test1 and test2. They were interpreted as indexing expressions and went straight to the class's subsref, just like this does:
>> t.CatsAndDogs
ans =
This is the overloaded method
because you executed these expressions outside the class, they were never interpreted as calls to test1 and test2. They were interpreted as indexing expressions and went straight to the class's subsref
Ah, exactly right. Thanks for that clarification. I've never used the method(instance) syntax rather than instance.method syntax so I didn't quite put it together that they would behave so differently. But your explanation is very clear.

Sign in to comment.

More Answers (1)

The problem is that subsref doesn't actually work like before. Consider this:
It's only because the programming logic in subsref is wrong. Here's a better version
function v = subsref(this, s)
if strcmp(s(1).type, '.') && strcmp(s(1).subs, 'child')
s=s(2:end);
if ~isempty(s)
v=subsref(this.child, s);
else
v=this.child;
end
elseif strcmp(s(1).type, '()')
v = 'overloaded method';
else
v=builtin('subsref',this,s);
end
end

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Products

Asked:

Ben
on 24 Apr 2013

Community Treasure Hunt

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

Start Hunting!