Joe C
Joe C

Reputation: 2827

Cannot get function input w/o using ;

I defined the following class

classdef TimerManager < handle

methods (Access = private)
    function obj = TimerManager()
    end
end

methods (Static)
    function singleObj = getInstance(varargin)
        varargin{1}
        singleObj = TimerManager();
    end
end

methods
    function foo(obj)
    end

end

end

I found the following code works differently w/ or w/o ; Is this expected? or if I missed anything?

>> TimerManager.getInstance(0).foo()

ans =

 0

>> TimerManager.getInstance(0).foo();
Index exceeds matrix dimensions.

Error in TimerManager.getInstance (line 13)
        varargin{1}

If I use nargin in side getInstance, it is 0 if I put ; at the end.

Upvotes: 3

Views: 53

Answers (1)

Suever
Suever

Reputation: 65430

Your error has nothing to do with the semi-colon. This has to do with the way that MATLAB handles subscripted referencing of objects (subsref).

The (Detailed) Issue

In MATLAB, you cannot "chain" subscripted referencing. For example if we create a cell array, we can't immediately index into this cell array without first assigning it to a temporary variable:

X1 = {'X1', 'X2', 'X3'}{1}

Error: Unbalanced or unexpected parenthesis or bracket.

The same applies for accessing the property or method of an object which is returned by a function. In your case, TimerManager.getInstance returns an instance which you must first assign to a temporary variable before being able to access it's foo method.

instance = TimerManager.getInstance(0);
fooResult = instance.foo();

MATLAB makes an attempt to throw an error or warning when it thinks that you're trying to "chain" these subscript references together, but if there is a scenario where an order of subscript operations is valid, then it is unable to throw the appropriate error. You are experiencing one of those cases.

The syntax that you are using is something like the following:

a.b(c).d()

This is valid if a.b is an array of structs with a field of d which is a function handle. In this case, c is an index.

When MATLAB parses this, it's going to retrieve the value of a.b, then ensure that c is a positive integer (a valid index) and is within the bounds of the array a.b. Then once that's been confirmed, MATLAB will access the d field and invoke it.

If we go back to your code for a second, we can comment out the varargin{1} line and get a more useful error message.

TimerManager.getInstance(0).foo();

Subscript indices must either be real positive integers or logicals.

Ok so that kind of makes sense, MATLAB is treating TimerManager.getInstance as a struct array and trying to index into it with the 0 which is obviously invalid and results in the error.

With respect to the actual error that you reported, note above that I said that before applying subscript referencing on the supposed struct array, MATLAB needs to first get the current value of TimerManager.getInstance. Because MATLAB thinks that this is just a struct array it's not going to pass any input arguments to it and this is resulting in varargin being empty and the error that you're seeing.

So your statement is functionally the same as:

instance = TimerManager.getInstance;        % No input arguments
instance(0).foo()                           % Indexing error

Note that this does work if the "input" to getInstance is 1 since this is a valid index into the 1 x 1 array of TimerManager instances returned when you call Timermanager.getInstance with no inputs.

TimerManager.getInstance(1).foo();

Potential Solutions

Use a temporary variable

instance = TimerManager.getInstance(0);
fooResult = instance.foo();

Or use the method(obj) notation for invoking the method rather than the obj.method() notation.

foo(TimerManager.getInstance(0))

A Note on Octave

None of this is going to be an issue in Octave since it allows "chaining" these subscript references together without the need for a temporary variable.

Upvotes: 3

Related Questions