indexed object dot notation method gives scalar property

前端 未结 1 2016
余生分开走
余生分开走 2021-02-02 16:49

I\'m seeing an issue when I try and reference an object property after having used a dot notation to apply a method. it only occurs when I try to index the initial object

1条回答
  •  醉梦人生
    2021-02-02 16:58

    I would definitely call this a bug in the parser; A bug because it did not throw an error to begin with, and instead allowed you to write: obj.method.prop in the first place!

    The fact that MATLAB crashed in some variations of this syntax is a serious bug, and should definitely be reported to MathWorks.

    Now the general rule in MATLAB is that you should not "index into a result" directly. Instead, you should first save the result into a variable, and then index into that variable.

    This fact is clear if you use the form func(obj) rather than obj.func() to invoke member methods for objects (dot-notation vs. function notation):

    >> A = MyClass;
    >> A.procData.data       % or A.procData().data
    ans =
         []
    >> procData(A).data
    Undefined variable "procData" or class "procData". 
    

    Instead, as you noted, you should use:

    >> B = procData(A):    % or: B = A.pocData;
    >> [B.data]
    

    FWIW, this is also what happens when working with plain structures and regular functions (as opposed to OOP objects and member functions), as you cannot index into the result of a function call anyway. Example:

    % a function that works on structure scalar/arrays
    function s = procStruct(s)
        if numel(s) > 1
            for i=1:numel(s)
                s(i) = procStruct(s(i));
            end
        else
            s.data = abs(s.data);
        end
    end
    

    Then all the following calls will throw errors (as they should):

    % 1x2 struct array
    >> s = struct('data',{1 -2});
    
    >> procStruct(s).data
    Undefined variable "procStruct" or class "procStruct". 
    
    >> procStruct(s([1 2])).data
    Undefined variable "procStruct" or class "procStruct". 
    
    >> feval('procStruct',s).data
    Undefined variable "feval" or class "feval". 
    
    >> f=@procStruct; f(s([1 2])).data
    Improper index matrix reference. 
    

    You might be asking yourself why they decided to not allow such syntax. Well it turns out there is a good reason why MATLAB does not allow indexing into a function call (without having to introduce a temporary variable that is), be it dot-indexing or subscript-indexing.

    Take the following function for example:

    function x = f(n)
        if nargin == 0, n=3; end
        x = magic(n);
    end
    

    If we allowed indexing into a function call, then there would be an ambiguity in how to interpret the following call f(4):

    • should it be interpreted as: f()(4) (that is call function with no arguments, then index into the resulting matrix using linear indexing to get the 4th element)
    • or should it interpreted as: f(4) (call the function with one argument being n=4, and return the matrix magic(4))

    This confusion is caused by several things in the MATLAB syntax:

    • it allows calling function with no arguments simply by their name, without requiring the parentheses. If there is a function f.m, you can call it as either f or f(). This makes parsing M-code harder, because it is not clear whether tokens are variables or functions.

    • parentheses are used for both matrix indexing as well as function calls. So if a token x represents a variable, we use the syntax x(1,2) as indexing into the matrix. At the same time if x is the name of a function, then x(1,2) is used to call the function with two arguments.

    Another point of confusion is comma-separated lists and functions that return multiple outputs. Example:

    >> [mx,idx] = max(magic(3))
    mx =
         8     9     7
    idx =
         1     3     2
    
    >> [mx,idx] = max(magic(3))(4)     % now what?
    

    Should we return the 4th element of each output variables from MAX, or 4th element from only the first output argument along with the full second output? What about when the function returns outputs of different sizes?

    All of this still applies to the other types of indexing: f()(3)/f(3), f().x/f.x, f(){3}/f{3}.

    Because of this, MathWorks decided avoid all the above confusion and simply not allow directly indexing into results. Unfortunately they limited the syntax in the process. Octave for example has no such restriction (you can write magic(4)(1,2)), but then again the new OOP system is still in the process of being developed, so I don't know how Octave deals with such cases.


    For those interested, this reminds me of another similar bug with regards to packages and classes and directly indexing to get a property. The results were different whether you called it from the command prompt, from a script, or from a M-file function...

    0 讨论(0)
提交回复
热议问题