MATLAB Answers

1

Directly accessing a method of a returned object shadows argument list

Asked by Christian Heigele on 23 Mar 2018
Latest activity Commented on by Christian Heigele on 26 Mar 2018
Hi there. I have observed a weird issue:
I have a class that exposes a method which returns me an instance of another class.
classdef Factory
methods (Static)
function worker = getWorker(inputItems)
fprintf('No. of input arguments: %d\n', nargin);
worker = Worker();
end
end
end
classdef Worker
methods (Static)
function doSomething()
disp('Hello you');
end
end
end
When I call it like follows, everything works perfectly fine and all arguments in the getWorker method are where I'd expect them:
>> worker = Factory.getWorker(1); worker.doSomething()
No. of input arguments: 1
Hello you
However, when I use that returned instance directly, without assigning it to a variable. The arguments don't end up in the method, but rather the argument list is used as an index, for the returned objects (which could be an array ... and hence non-numeric inputs mess everything up even more...):
>> Factory.getWorker(1).doSomething()
No. of input arguments: 0
Hello you
And my actual usecase would be the following, where my getWorker method does not have / need any input arguments, but then I get a warning:
>> Factory.getWorker().doSomething()
No. of input arguments: 0
Warning: A value of class "Worker" was indexed with no subscripts specified. Currently
the result of this operation is the indexed value itself, but in a future release, it
will be an error.
Hello you
Does anyone has an input, how I can enforce that the arguments end up in the right place, without assigning a real instance?
Used versions: Matlab 2017a and b on a Windows10 machine.

  0 Comments

Sign in to comment.

Products

1 Answer

Answer by Guillaume
on 23 Mar 2018
 Accepted Answer

I remember reading somewhere (probably on Answers) that dot indexing the result of a method is not officially supported in matlab. Matlab does try to make it work but can't always succeed.
The problem is that
Factory.getWorker(x).doSomething
is ambiguous. Is it call getWorker with one argument, x, and use doSomething on the result returned by that method, or is it call getWorker with no argument, get the x element of the array returned by getWorker and use doSomething on that element?
Clearly, matlab choses the 2nd interpretation. I don't think there's any other way to remove the ambiguity other than creating assigning the result of getWorker to a variable. Maybe it could be made to work by calling subsref directly, but for static methods, I'm not even sure you can use subsref.

  3 Comments

Hm, yes, that's also what I'm afraid of :(
For none-static methods, I could also call it like that:
doSomething(Factory.getWorker(1))
But that Syntax is not so nice :(
Plus, I don't think it is a real ambiguity, b.c. otherwise, also the call Factory.getWorker(1) itself would be ambiguous.
Well, clearly it's ambiguous since you want it to be function call with one argument, but the parser sees it as a function call with no argument + indexing into the result.
Matlab does not normally allows you to index directly into the result of a function call, that is:
a(row, col)
a{row, col}
a.prop
require that a is a variable not a function. Those three lines all get translated into a call to subsref
subsref(a, struct('type', '()', 'subs', {row, col}))
subsref(a, struct('type', '{}', 'subs', {row, col}))
subsref(a, struct('type', '.', 'subs', 'prop'))
As said, I remember reading somewhere that matlab does try to make the dot indexing work when a is a function but it's not officially supported.
In any case, since it doesn't work in your circumstances, you don't have a choice but creating an intermediate variable.
Hmm,
I'm not fully convinced, but at least can accept that it is like that.
What I found out, that if I instantiate the Factory, I can easily call it, and get the expected results:
>> fact = Factory();
>> fact.getWorker(1).doSomething()
No. of input arguments: 1
Hello you
And even better, this also works with an inline instantiation:
>> Factory().getWorker(1).doSomething()
No. of input arguments: 1
Hello you
Which is not 100% nice, but okay enough for me.

Sign in to comment.