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

I would like to overload only one type of subsref calls (type '()) for a particular class and leave any other Matlab calls built into subsref - in particular, I want Matlab to handle access to properties / methods via'. ' a type. But it seems that the Matlab built-in function does not work when subsref is overloaded in the 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 the following:

 t = TestBuiltIn; t.testprop >> This is the overloaded method 

This is as expected. But now I want to call Matlab, which is built into the subsref method. To make sure that I'm doing it right, first try a similar call in the structure:

 x.testprop = 'Accessed correctly'; s.type = '.'; s.subs = 'testprop'; builtin('subsref', x, s) >> Accessed correctly 

As expected. But, when I try to use the same method on TestBuiltIn:

 builtin('subsref', t, s) >> This is the overloaded method 

... Matlab calls the overloaded method, not the built-in method. Why does Matlab call an overloaded method when I asked it to call an inline method?

UPDATE: In response to the @Andrew Janke answer, this solution almost works, but not quite. Consider this class:

 classdef TestIndexing properties prop1 child end methods function this = TestIndexing(n) if nargin==0 n = 1; end this.prop1 = n; if n<2 this.child = TestIndexing(n+1); else this.child = ['child on instance ' num2str(n)]; end end function v = subsref(this, s) if strcmp(s(1).type, '()') v = 'overloaded method'; else v = builtin('subsref', this, s); end end end end 

It all works:

 t = TestIndexing; t(1) >> overloaded method t.prop1 >> 1 t.child >> [TestIndexing instance] t.child.prop1 >> 2 

But this does not work; it uses the built-in subsref for the child, not the overloaded subsref:

 t.child(1) >> [TestIndexing instance] 

Note that the above behavior is incompatible with both of these behavior (as expected):

 tc = t.child; tc(1) >> overloaded method x.child = t.child; x.child(1) >> overloaded method 
+6
source share
4 answers

It is possible, IIRC. To change () , but not {} and '.', Write your subsref method to pass these other cases along with the built-in subsref from your overloaded subsref instead of trying to explicitly call the built-in from the outside.

 function B = subsref(A, S) % Handle the first indexing on your obj itself switch S(1).type case '()' B = % ... do your custom "()" behavior ... otherwise % Enable normal "." and "{}" behavior B = builtin('subsref', A, S(1)) end end % Handle "chaining" (not sure this part is fully correct; it is tricky) orig_B = B; % hold on to a copy for debugging purposes if numel(S) > 1 B = subsref(B, S(2:end)); % regular call, not "builtin", to support overrides end end 

(And if this builtin call does not work, you can simply insert cases that use . And {} directly, because subsref overloading subsref ignored inside the class definition.)

To make it fully functional, you may need to change B to varargout and add chain behavior to the case of "()".

+4
source

To expand the explanation provided on the Mathworks board , the built-in function works only from the overloaded method to access existing (built-in) methods.

Method overloading in Matlab effectively obscures the inline implementation from everything except the method that performs the shadowing, and the method that performs shadow monitoring must use the built-in access for the inline implementation instead of returning to itself.

+1
source

Generally. You must use builtin(m,s) inside a function that has been overloaded. This is clearly indicated in the MATLAB documentation.

http://www.mathworks.com/help/matlab/ref/builtin.html

builtin (function, x1, ..., xn) performs the builtin function using input arguments from x1 to xn. Use the inline version to execute the original inline from a method that overloads the function. To work correctly, you should never overload the built-in functions.

Consider this code:

 classdef TestBuiltIn properties testprop = 'This is the built in method'; testprop2 = 'This is the derived subsref '; end methods function v = subsref(m, s) disp('enter subsref no matter how!'); v = builtin('subsref',m, s); end end end 

and testing team

 clear; t = TestBuiltIn; builtin('subsref', t, s) s.type = '.'; s.subs = 'testprop'; s2 = s; s2.subs = 'testprop2'; >> builtin('subsref', t, s1) enter subsref no matter how! ans = This is the derived subsref >> builtin('subsref', t, s) enter subsref no matter how! ans = This is the built in method 
0
source

In the updated version of this problem, when t.child(1) is called, the t.child(1) function will receive the argument s with s(1).type='.', s(1).subs='child' and s(2).type='()', s(2).subs='1' . Evaluation of this expression is not performed in stages, as mentioned in his answer to Andrew Janke . As a result, when overriding subsref you need to process this chain of operations by first processing ".". operator. Below is an incomplete example of your case,

 function v = subsref(this, s) switch s(1).type case '.' member = s(1).subs; if ismethod(this, member) % invoke builtin function to access method member % there is issue about the number of output arguments v = builtin('subsref',this,s); elseif isprop(this, member) % property if length(s) == 1 % invoke builtin function to access method member v = builtin('subsref', this, s); elseif length(s) == 2 && strcmp(s(2).type,'()') % this is where you evaluate 'tc.child(1)' else % add other cases when you need, otherwise calling builtin end else % handling error. end case '()' % this is where you evaluate 't(1)' % you may need to handle something like 't(1).prop1', like the '.' case otherwise % by default, calling the builtin. end end 

You can also find a detailed code example and instructions on Code Templates for the subsref and subsasgn methods .

Another thing you might need to know is that members of this class will also be called via subsref with. operation. Look at this topic subsref on classes: how to send methods? , you will find that the builtin function has no return value (since the called method has no return value). However, the builtin return value builtin assigned to v (even if v is replaced with varargout ), which is an obvious error. The author also gives a workaround using try ... catch to fix this error.

0
source

Source: https://habr.com/ru/post/943560/


All Articles