I'm working on rewriting an old MATLAB package. As part of that rewrite I'm updating two classes (lets call them old_class1 and old_class2) defined using the class() function to classes defined with classdef.
The definition of old_class1 contains the line superiorto('old_class2'). This function is not allowed in a constructor defined with classdef, but I am unable to find any equivalent. How do I create functionality equivalent to superiorto() in a class defined with classdef?
superiorto is no longer available in MATLAB, but I was able to find a copy of old documentation that indicates it was used to determine which object's method was called when multiple different classes were given as function arguments. For example, given obj1=class1() and obj2=class2(), with the class1 constructor containing superiorto('class2'), would cause function(obj1,obj2) to callclass1.function, rather thanclass2.function`.
With modern classdef functionality, the same can be accomplished by setting the InferiorClasses property:
classdef (InferiorClasses = {?class2}) class1
Related
I tried to change an attribute value of a class by invoking one of its member function:
p1 = tank();
p1.checkOri(p1);
And in the class definition, I have that static method:
classdef tank
properties
value
...
end
methods
...
methods (Static)
function obj = checkOri(obj)
if (CONDITION) %the thing I want it to do
obj.value = EXPRESSION;
...
Yet this checkOri method is not working. But if I write this method in the main file, or to say altering the value of p1-the instance of class tank-it works perfectly:
p1 = tank();
p1.checkOri(p1);
if (CONDITION) %the thing I want it to do
p1.value = EXPRESSION;
It works perfectly.
I wonder what caused this. From my experience with other programming languages, invoking method should have worked, is it because of some tricks with Matlab syntax or static method? How could I fix it so that this method would work?
So, as #Navan in the comment said, handle class could be a solution.
It appears Matlab has a similar parameter concept with Java and C++, arguments modified in a function/method only remains that modification inside the function/method.
For this class, I simply added < handle in the head of class definition and it worked:
classdef tank < handle
properties
...
But I am not sure if that is the only solution, there might be better ways to do this. So I'll leave that question open, you are more than welcomed to post your opinion:D
In MATLAB, the call
p1.checkOri();
is equivalent to
checkOri(p1);
In both cases, the class method checkOri is called for the class of object p1, passing p1 as first argument to the function by value.
Because p1 is passed by value, any changes made to it inside the function are not seen by the object in the calling workspace. Therefore, one typically does
p1 = checkOri(p1);
This way, the object that was passed by value and modified inside the function is passed back out and assigned to the variable that held the original object.
If the method is written as follows:
function obj = checkOri(obj)
%...
end
then MATLAB will optimize the above function call such that no copy of the object is actually made. Note that both in the function declaration and in the function call, the input and output variable is the same.
As already discovered by OP, the above does not hold for handle classes, classes that inherit from handle. These classes act as if they are always passed by reference, and any change made to them in any workspace will be reflected in all other copies in other workspaces.
Also assigning to a member variable does not follow the above, such that
p1.value = 0;
modifies object p1.
For more information on the difference between value classes and handle classes see this other question.
After evolving my project code for months, I've finally hit a need to define a new class. Having to romp through my previous class definitions as a refresher of the conventions, I noticed that all constructors and property setters all have an output argument, even though nothing is assigned to it, e.g.:
function o = myConstructor( arg1, arg2, ... )
function o = set.SomeProperty( o, arg1 )
I've been looking through the documentation for upward of an hour without finding the explanation for this. It doesn't look like it depends on whether a function is defined in the class definition file or in its own separate m-file.
Can anyone please explain?
The best place to start is the documentation "Comparison of Handle and Value Classes". From the very top:
A value class constructor returns an object that is associated with the variable to which it is assigned. If you reassign this variable, MATLABĀ® creates an independent copy of the original object. If you pass this variable to a function to modify it, the function must return the modified object as an output argument.
A handle class constructor returns a handle object that is a reference to the object created. You can assign the handle object to multiple variables or pass it to functions without causing MATLAB to make a copy of the original object. A function that modifies a handle object passed as an input argument does not need to return the object.
In other words, value classes need to return a modified object (which is a new object distinct from the original), while handle classes don't. The constructor of either class will always have to return an object, since it is actually constructing it.
Some good additional reading is "Which Kind of Class to Use", which links to a couple helpful examples of each type of class object. Looking at the DocPolynom value class example, you can see that property set methods have to return the modified object, while the dlnode handle class example only requires an output for its constructor. Note that you could still return an object from a handle class method (if desired), but it's not required.
I defined a class in one of my many MATLAB packages. To my suprise, I could not access a constant property of my class without importing the class definition. Even if it is a method of the class itself. Like so:
classdef TestClass
properties( Constant )
c=0;
end
methods
function obj = TestClass()
end
function getC(obj)
import test.TestClass;
disp(TestClass.c);
end
end
end
I just want to check whether I am doing something wrong here or is this the correct way to use constants in MATLAB.
Since you have placed TestClass inside a package Matlab needs to know where to look to find the definition for this class, even if it's a reference from within the class or function. An alternate to the above code could be:
function getC(obj)
disp(test.TestClass.c);
end
Alternately, if within a class, constant values can be accessed from the object itself.
function getC(obj)
disp(obj.c);
end
If neither of these is working for you, you may need to refresh the classdef for TestClass from memory. This will cause matlab to reload the constant value, which is pulled into Matlab when it first parses the classdef file to determine the structure of the class. This can be done using clear classes, however a warning that it will also clear all other classes, variables, and any breakpoints you have set.
If you want to see if this is necessary you can view the metaclass object to determine what Matlab "thinks" your class structure should be. You can do this using the following.
mc = ?test.TestClass;
mc.PropertyList
You may need to index into the property list to find the specific property you are interested in, but the thing you are looking for are the following fields.
Name: 'c'
Constant: 1
DefaultValue: 0
I wish to add a method called nansubset to the table class. Essentially it allows you to call T(r,c) where r and c are real positive integer vectors possibly containing NaN's.
Stubbed code for nansubset.m could be:
function T = nansubset(T, r, c)
T = T(r,c);
end
I am following the instructions here, which detail how to add a new method to the cell class. Basically, in a folder on my Matlab path, I create a folder called #table, and within this folder, create a file called nansubset.m.
I am getting the following problems:
>> tmpT = table(); nansubset(tmpT, 1, 1)
Undefined function 'nansubset' for input arguments of type 'table'.
and
>> doc #table/nansubset
Your search - #table/nansubset - did not match any documents.
However:
edit nansubset
and
edit #table/nansubset
both open the method file in my editor.
Further, I followed the instructions in the above link to add the plus method to the cell class and find that it works perfectly.
Can someone please explain to me how I can add this additional method to the table class?
With the release of Matlab R2012b (version 8), the class folder behavior changed (emphasis is mine):
In MATLAB Versions 5 through 7, class folders do not shadow other class folders having the same name, but residing in later path folders. Instead, the class the combination of methods from all class folders having the same name define the class. This is no longer true.
For backward compatibility, classes defined in class folders always take precedence over functions and scripts having the same name, even those that come before them on the path.
The combination of the two bold statements explains the behavior:
cell is a built-in Matlab function that predates the new OOP rules that returns an instance of its class. And before R2012b, adding methods to a class folder called #cell added the methods to the object returned from the cell function (which isn't defined with a classdef nor a class folder); this ability was retained for compatibility with legacy user code.
table was added after R2012b, is defined via a class folder, and is Sealed. Since it is Sealed, it cannot be subclassed. And with the new rules, any #table folder without an associated classdef file will not register as a class folder nor will its methods be composed into the existing class unless it is part of the legacy system (like cell).
I can see three workarounds listed in the order I think is best:
Have a function on the Matlab path, just like the one you have, and always call the "method" using function notation instead of dot notation. If you need more "methods" group them in a folder or package (if good namespacing is desired) on the path. Since table is a value class, this option doesn't seem bad.
Create a wrapper class like the one below. It is cumbersome but automatically encapsulates the additional functions.
classdef MyTable < handle
properties
tab;
end
methods
function mytab = MyTable(varargin)
mytab.tab = table(varargin{:});
end
function tabnan = nansubset(mytab,r,c)
tabnan = mytab.tab(r,c);
end
end
end
Create a local copy of [matlabroot,'\toolbox\matlab\datatypes\#table\*'] and add the methods directly. I can't think of any huge drawbacks to this per se, but it feels weird copying internals like this.
I've got a signature for a method that looks like this:
private IEnumerable BuildCustomerUpdatePlan(List localCacheChangedCustomers, List crmChangedCustomers){}
When I look at the moled object, the syntax (IntelliSense) of how to call the method and test itis absolutely confusing to me and every time I give it a shot, I get compilation errors. I've looked through the basic tutorials provided on MSFT's site, but I simply don't get how to test a private method using Moles or how to deal with the return type and multiple parameters.
Unfortuantely I've been unable to find other good HOWTO's or threads demonstrating a more complex sample than just working with a simple Add() method that spits out an INT and accepts an INT. :(
Tips?
In your testing project, first make sure you add a Moles assembly corresponding to the assembly-under-test. You'll also want to add an using statement of the assembly-under-test with .Moles appended so you can use the moled assembly.
Moles changes the names of the classes and methods to the form M[Original Class Name].[Original Method Name][typeof param1][typeof param2].... In your case a detour for that method could look like MClass.BuildCustomerUpdatePlanListList = (List x, List y) => { [code]};. That defines an anonymous method that takes two Lists as parameters and you'd put whatever code wanted in the function. Just make sure that you return an IEnumerable in that anonymous method.
Here's an example using Moles to detour Directory.GetFiles:
using System.IO.Moles;
[assembly: MoledType(typeof(System.IO.Directory))]
...
MDirectory.GetFilesStringString = (string x, string y) => new string[0];
Since the Directory class is a member of System.IO I use using System.IO.Moles; to specify that I want to use moled members of the assembly.
Moles requires you to specify the types Moled: [assembly: MoledType(typeof(System.IO.Directory))] does the job.
Finally, Directory.GetFiles takes two strings as parameters and returns a string array. To detour the method into returning the equivalent of no files found, the moled method just returns new string[0]. Curly braces are needed if you want multiple lines in the anonymous method and, if not detouring a void method, a return statement that matches the type the original method would return.