Search code examples
matlaboopmethodssyntaxmatlab-class

Difference between "OOP" and "functional" method invocation syntax


On this page that explains the use of inputParser class,

we see that every inputParser method call in the examples is of the form

methodname(object, arguments)

instead of

object.methodname(arguments)

For example

addRequired(p,'filename',@ischar)

instead of

p.addRequired('filename',@ischar)

where p is an instance if inputParser.

I would say that this makes it unclear where addRequired is coming from without having to search for it either though which or for the instantiation line in the code before it is being called. Having addRequired available in any context kind of breaks encapsulation, and seems to be the very opposite of what you would want from introducing OOP in the first place.

I suspect there is a good reason to sacrifice readability and write documentation in this particular way.

So my question is, is there any practical difference between "functional" and "OOP" syntax in MATLAB?


Solution

  • I'm afraid these syntaxes are not even fully equivalent, as can be learned from the following example:

    >> f = fit( (1:3).', (2:2:6).' ,'poly1')
    f = 
         Linear model Poly1:
         f(x) = p1*x + p2
         Coefficients (with 95% confidence bounds):
           p1 =           2  (2, 2)
           p2 =  -6.784e-16  (-4.709e-14, 4.574e-14)
    >> methods(f)
    Methods for class cfit:
    
    argnames       cfit           coeffvalues    dependnames    feval          formula        integrate      numargs        plot           probnames      setoptions     
    category       coeffnames     confint        differentiate  fitoptions     indepnames     islinear       numcoeffs      predint        probvalues     type           
    
    >> f.coeffvalues
    Error using cfit/subsref (line 18)
    The name 'coeffvalues' is not a coefficient or a problem parameter.  You can only use dot notation to access the coefficients and problem parameters of a cfit or sfit, e.g.,
    'f.p1'.
    
    For the current fit, you can access these properties: p1, p2
    
    You can get coefficient names and values either by name, e.g., p1 = f.p1, or by using the coeffnames or coeffvalues functions, e.g., names = coeffnames(f).
    
    To use methods, use functional notation instead, e.g., plot(f). 
    
    >> coeffvalues(f)
    ans =
        2.0000   -0.0000
    

    Most importantly:

    To use methods, use functional notation instead, e.g., plot(f).

    Now suppose we are sadists and want to write a function that behaves like that ourselves, investigating further we find that cfit.coeffvalues is simply a getter for a private property. Now if you look closely at the error above, you'd notice that it didn't even occur in cfit.coeffvalues, but instead in cfit.subsref!

    In conclusion,

    from this we can learn, empirically, that the functional notation goes directly to the method in question, whereas the OOP notation first goes through the possibly overridden subsref method of the class. I guess if you want to make sure you're skipping any custom subsref, use functional notation.