How to avoid recursion with parenReference

조회 수: 17 (최근 30일)
Mike Falcinelli
Mike Falcinelli 2021년 10월 25일
편집: James Lebak 2023년 9월 12일
Using Matlab 2021B version
I create a class which inherits both handel & matlab.mixin.indexing.RedefinesParen.
classdef Abc <handle & matlab.mixin.indexing.RedefinesParen
I create object arrays using this class.
I want to overload the parenthesis for the class so that it can perform special handling in addition to indexing into the object array ( normal operation ).
For example
Abc('special') - performs special handling
Abc(2:3) - down selects only objects 2 to 3 (normal operation without RedefinesParen)
I have written the parenReference function as follows
function varargout = parenReference(obj,indexOp)
if isscalar(indexOp)
varargout{1} = obj(indexOp(1).Indices);
else
% Other special handling and forward indexing
%
end
end
The problem is that no matter how I try to select the subset of objects to return in the third line, it calls parenReference recusively and faults when recursion limit is reached. I have even tried
varargout{1} = builtin('subsref',obj,substruct('()',indexOp(1).Indices))
How do I select a subset of obj in this function without it being called recursively.
Thanks
  댓글 수: 9
Matt J
Matt J 2023년 9월 11일
편집: Matt J 2023년 9월 11일
@James Lebak Is there any reason for MathWorks not to offer a syntax for the builtin() command like the following,
tmp=builtin('parenReference',obj,indexOp);
that will call built-in ()-indexing when the user truly wants it? As it stands now, I don't think there is a solution to the OP's recursion issue without something like this.
James Lebak
James Lebak 2023년 9월 12일
편집: James Lebak 2023년 9월 12일
The OP's request can't be accomplished with RedefinesParen. If you inherit from RedefinesParen, your object is always a scalar, and you have to have a property inside the object (or something else) that is the array. The usual paradigm is then to have parenReference/parenAssign index into that other entity, and then there's no recursion problem (because the property is a different class and presumably uses built-in indexing). Internally we call this the 'scalar masquerading as an array' pattern, and it's the only thing RedefinesParen supports. The reason RedefinesParen doesn't have a concept of 'calling builtin parenReference' is that it's really not needed for the specific cases that RedefinesParen handles -- which do not, unfortunately, include the OP's use case.
Subsref and subsasgn support the 'scalar masquerading as an array' pattern, but they also allow you to override indexing into arrays like the OP is trying to do -- for example, to translate character strings into numerical indices. This allows the object to be a built-in array, and also requires some sort of 'map the indices and call built-in paren-indexing' capability as you are suggesting. When we designed RedefinesParen we decided to separate these use cases. If we provided the 'override indexing into arrays' functionality in a modular indexing mixin, we would provide something like the builtin parenReference/parenAssign calls that you're suggesting, and eventually I do hope to provide this functionality. But I think you're correct that the OP's request requires subsref/subsasgn as things currently stand.

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

채택된 답변

Matt J
Matt J 2021년 11월 1일
편집: Matt J 2021년 11월 1일
Classic subsref doesn't seem to difficult in this case. You can't beat the classics!
function varargout = susbref(obj,S)
if S(1).type~="()"
[varargout{1:nargout}] = builtin('subsref',obj,S); return
end
T=S(2:end);
S=S(1);
if isscalar(S.subs) && isscalar(S.subs{1})
out = obj(S(1).subs{1});
else
% Other special handling and forward indexing
%
out=...
end
[varargout{1:nargout}] = builtin('subsref',out,T);
end
  댓글 수: 7
Thomas Michiels
Thomas Michiels 2023년 9월 8일
@Matt J understandable. it is so strange to me that you cannot access the original indexing operator anymore. i have to agree with you in this case
Matt J
Matt J 2023년 9월 8일
@Thomas Michiels Stranger still that you can access the original operator when using RedefinesDot, see my comment above.

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

추가 답변 (1개)

Shanmukha Voggu
Shanmukha Voggu 2021년 10월 28일
Hi Mike,
The recursion limit is reached because the parenReference is calling itself recursively,
The solution is to create a property that holds the given array in the class Abc
properties (Access=private)
copyOfArray
end
And in the constructor of class Abc assign the given array to the property above
function obj = Abc(arr)
obj.copyOfArray = arr;
end
Now you can use indexing on the property to get the desired results, Instead of using below statement in parenReference function
varargout{1} = obj(indexOp(1).Indices);
use the following statements
obj.CopyOfArray = obj.CopyOfArray.(indexOp(1));
varargout{1} = obj; %if you want output as object array, or use obj.copyOfArray in order to have array alone as output
Refer this for more information.
  댓글 수: 6
Matt J
Matt J 2021년 11월 2일
편집: Matt J 2021년 11월 3일
developers inside and outside the company repeatedly told us that they often experienced behavior that they didn't expect because of the rule
It's definitely something people new to Matlab OOP don't initially grasp, but I greatly worry that the recursion pitfall will be highly prevalent without it, in both of the use cases that you've described. It makes me very nervous about embracing the new Redefines.
In particular, if you overload dot, paren, or brace, there's no good way to invoke your own overloaded indexing behavior inside your class, short of an explicit call to subsref/subsasgn.
Seems easy enough to outsource the work to a class-related function or external function, if you really do need a workspace where the overloaded indexing needs to be in force. I personally have never had to do that.
James Lebak
James Lebak 2021년 11월 5일
편집: James Lebak 2021년 11월 5일
I want to offer reassurance that in our experience with using the modular indexing APIs internally, we haven't found recursion to be a big problem. The APIs don't currently do everything that subsref and subsasgn can, but I would hate to see you avoid them just because of the potential to encounter this problem.
It's true that it's easy to write code that encounters the recursion, and we did see developers new to the API write this code. In the case that RedefinesParen is primarily designed for, the scalar that presents itself as an array, we also found it to be a relatively easy problem to avoid, and to be easily uncovered by simple testing.
We are currently moving several MathWorks classes from subsref and subsasgn to modular indexing and in our production test system, we haven't encountered failures due to modular indexing classes unexpectedly calling overloaded indexing recursively.

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

카테고리

Help CenterFile Exchange에서 Customize Object Indexing에 대해 자세히 알아보기

제품


릴리스

R2021b

Community Treasure Hunt

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

Start Hunting!

Translated by