Matlab copy constructor - matlab

Is there a better way to implement copy construcor for matlab for a handle derived class other than adding a constructor with one input and explicitly copying its properties?
obj.property1 = from.property1;
obj.property2 = from.property2;
etc.
Thanks,
Dani

There is another easy way to create copies of handle objects by using matlab.mixin.Copyable. If you inherit from this class you will get a copy method which will copy all the properties for you.
classdef YourClass < matlab.mixin.Copyable
...
a = YourClass;
b = copy(a); % b is a copy of a
This copy method creates a copy without calling constructors or set functions of properties. So this should be faster. You can also customize the copy behavior by overriding some methods.

If you want a quick-and-dirty solution that assumes all properties can be copied, take a look at the PROPERTIES function. Here's an example of a class that automatically copies all properties:
classdef Foo < handle
properties
a = 1;
end
methods
function F=Foo(rhs)
if nargin==0
% default constructor
F.a = rand(1);
else
% copy constructor
fns = properties(rhs);
for i=1:length(fns)
F.(fns{i}) = rhs.(fns{i});
end
end
end
end
end
and some test code:
f = Foo(); [f.a Foo(f).a] % should print 2 floats with the same value.

You can even use
try
F.(fns{i}) = rhs.(fns{i});
end
which makes the method more useful

Related

Program in same OOP style as App Designer

I like the OO programming style that matlabs App Designer uses (or at least the way I'm using it). Now I'm wondering if I can use the same style in my "normal" matlab class.
What I have now:
classdef myClass
properties
myVar;
end
methods
function Main(obj)
obj.myVar = "a";
obj = DoSomething(obj);
disp(obj.myVar) % outputs "c"
end
function obj = DoSomething(obj)
if(obj.myVar == "a")
obj.myVar="c";
else
obj.myVar = "b";
end
end
end
end
Which can be called externally using:
myClassInst = myClass;
myClassInst.Main()
I would like to get rid of all the "obj = " in the classdef, as is possible in App Designer. So something that would look like this:
classdef myClass
properties
myVar;
end
methods
function Main(obj)
obj.myVar = "a";
DoSomething(obj); % Just call the function without "obj = "
disp(obj.myVar) % outputs "a" because I didn't overwrite obj
end
function DoSomething(obj)
if(obj.myVar == "a")
obj.myVar="c";
else
obj.myVar = "b";
end
end
end
end
The equivalent of this seems to work in App Designer. So it appears you can modify variables in a class (instance?) in App Designer, while also being able to access the modified variable without explicitly overwriting your old class instance.
I noticed App Designer has all methods an properties set to (Access = private), though I'm not sure that has anything to do with it. Of course if I set everything to private, then I can't access the Main() method from outside anymore.
So my question is, how can I program in "normal" matlab, the same way as is possible in App Designer?
EDIT:
The following works in App Designer (I left out the methods/properties for the GUI elements):
classdef tmp < matlab.apps.AppBase
properties (Access = private)
myVar; % Description
end
methods (Access = private)
function doSomething(app)
if app.myVar == "a"
app.myVar = "c";
else
app.myVar = "b";
end
end
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
app.myVar = "a";
doSomething(app);
disp(app.myVar); % outputs "c"
end
end
end
You definitely can! All you have to do is inherit from the handle class, as opposed to a value class which is the default for matlab. You can also define private and public methods as in other languages.
The only thing you have to do is:
classdef myclass < handle % this is how you inherit from base class
properties
public_property
end
properties (Access=private)
private_property
end
methods
function obj = myclass() % class constructor
...
end
function public_function()
...
end
end
methods (Access=private)
function private_function()
...
end
end
end
Now every time you pass an object of this class to a function, you are not passing it by value, you are passing by reference (as you might be used to from python) and modifying it's properties modifies them also in the original object.
You need to inherit (< at the top of the class) from a handle class
classdef myClass < handle
properties
var
end
methods
function obj = myClass( varargin )
% Constructor function, called automatically when object is created
end
function someFunction( obj )
obj.randomizeVar(); % Equivalent to randomizeVar( obj );
end
function randomizeVar( obj )
obj.var = rand();
end
end
end
See the documentation for the difference between a "handle" and "value" class:
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. For information on value-class behavior, see Avoid Unnecessary Copies of Data.
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.
Moreover, if you edit matlab.apps.AppBase, the class which you app designer code inherits, you can see that the first line is
classdef AppBase < handle
So you are literally doing the same thing, without the AppBase middle-man.

How to run batch jobs in Matlab using parcluster, if I want to run a method of a class

I want to run jobs in Matlab using batch, with parcluster. each job should use an existing class, and run one of it's methods. I can make It work without parcluster, but with parcluster I get an error.
without parpool, this works:
define a class with a simple method:
classdef myclass
properties
prop;
end
methods
% constructor
function obj = myclass()
obj.prop = 0;
end
% add function
function obj = add(obj,a)
obj.prop = obj.prop + a;
end
end
end
create an object and use it's function:
obj = myclass();
obj = add(obj,1);
this works. but when I try to run the same thing in batch I get an error. here is what I'm doing:
c = parcluster();
j = batch(c,#myclass,1,{});
wait(j);
r = fetchOutputs(j);
obj = r{1};
j = batch(c,#add,1,{obj,1});
the last line gives an error:
warning unable to calculate the dependencies of the files:
add
because: file, function or class "add" may not exist.
how can I run class methods in batch?
The most robust way of specifying a method of a class in an anonymous function is to use the dot notation
B = batch(c, #obj.add, 1, {1});
wait(B)
%// Re-assign results to obj (see note below)
obj = fetchOutputs(B);
This helps MATLAB to resolve myclass.add better as it is more explicit. The way that you had written it previously, MATLAB is looking for a regular function named add and is unable to find it. It does not consider the types of the input (which in your case would be required to know that it is a method).
Note: batch will make a copy of your object when you pass it as an input. Because of that, you will need to explicitly grab the output and re-assign to obj because the original obj will not be modified in-place.

In MATLAB, is it possible to check if an object already exists before creating a new one?

I'm trying to figure out how to ask the user whether they want to replace the previous object of the same class with the default object, or simply use the previous object, when calling the constructor.
I'm looking for actions in both these cases:
>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): y
%clear obj and call default constructor to create new obj
>>obj = Obj()
'obj' already exists. Replace it with default? (y/n): n
%cancel call of Obj()
How would I do this? I've messed around with the default constructor, to no avail.
EDIT: If it makes any difference, Obj is a subclass of Handle.
The following solution stems from several workarounds/hacks and is not part of the standard MATLAB's OO constructs. Use with caution.
You need to:
evalin() into the 'caller' workspace the names and classes of the 'base' workpsace variables
retrieve the last executed command
extract the name of the assigned variable with e.g. regexp()
compare names and classes. If a total match occurs, i.e. the variable in the 'base' workspace is being overwritten with a new instance of the same class, ask the user for input(). If the user chooses to preserve the existing object, overwrite the new instance with the existing one through evalin('caller',...).
The class foo:
classdef foo < handle
properties
check = true;
end
methods
function obj = foo()
% variable names and sizes from base workspace
ws = evalin('base','whos');
% Last executed command from window
fid = fopen([prefdir,'\history.m'],'rt');
while ~feof(fid)
lastline = fgetl(fid);
end
fclose(fid);
% Compare names and classes
outname = regexp(lastline,'\<[a-zA-Z]\w*(?=.*?=)','match','once');
if isempty(outname); outname = 'ans'; end
% Check if variables in the workspace have same name
idx = strcmp({ws.name}, outname);
% Ask questions
if any(idx) && strcmp(ws(idx).class, 'foo')
s = input(sprintf(['''%s'' already exists. '...
'Replace it with default? (y/n): '],outname),'s');
% Overwrite new instance with existing one to preserve it
if strcmpi(s,'n')
obj = evalin('caller',outname);
end
end
end
end
end
Class in action:
% create class and change a property from default (true) to false
clear b
b = foo
b =
foo with properties:
check: 1
b.check = false
b =
foo with properties:
check: 0
% Avoid overwriting
b = foo
'b' already exists. Replace it with default? (y/n): n
b
b =
foo with properties:
check: 0
The weaknesses (see points above):
applies only to cmw line and script executed commands, not functions (see link to extend to function calls). Also, might break in case of problems reading history.m.
the current regex fails on a==b.
Dangerous because the evalin() on user input leaves potential security threats open. Even if the input is filtered with the regexp and the string comparison, the construct might pose a problem if the code is revisited later on.
Singleton
try this, not sure if you are familiar with it, but this mean, you only have one global instance of this specific object.
You could use the function isobject() (see doc here) to check if the variable is an object. If true, you could then check the class of the object with class() (see doc here) and compare it to the class of the object you want to build. Something like (just to give you an idea):
if isobject(obj)
if class(obj) == myclass
% ask to replace it or not
else
% create new one over the object of a different class
end
else
% create new one
end
If I understand your question correctly, you probably want to put this as a constructor function for your class. I think you will have to pass the variable name when calling the constructor: obj = Obj(obj).

How do I define a class in MATLAB that uses methods defined in separate files (in an #-folder)?

I would like to define a class in one file, and its methods in several other files.
Apparently, the way to do this is to create a subfolder named #<ClassName>in the class folder, and to put all the method files in the so-called "#-folder".
However, once I've made the #-folder, I'm not sure what to put in the class-definition file to make it aware of the methods in the #-folder.
classdef myClass
properties
myProperty = 0;
end
methods
%#
%# --- What goes here? ---
%#
end
end
You declare the function signature without the function keyword, and with a semicolon at the end.
classdef myClass
properties
myProperty = 0;
end
methods
retval = my_function ( arguments );
end
end
Then MATLAB will go looking for a file called ../#MyClass/my_function.m.

Is it possible to hide the methods inherited from the handle class in matlab?

I'm working on a command line application for ultrasound simulation in MATLAB. Nearly every object in our code is a subclass of handle (to pass as references). The problem I'm having is that all the methods inherited from the handle class shows up under the "Methods" section in MATLAB (see example below).
What I want is to hide the inherited methods from the handle class so that only the function the user is allowed to use is shown under "Methods". This way it doesn't look so messy for the user if he/she wants to know which methods to use.
Example Test class:
classdef Test < handle
methods
function myFunction(obj)
end
end
end
In the command line:
T = Test()
T =
Test handle with no properties.
Methods, Events, Superclasses
After clicking on "Methods":
Methods for class Test:
Test delete findobj ge isvalid lt ne
addlistener eq findprop gt le myFunction notify
What I want:
Methods for class Test:
Test myFunction
Is this possible in MATLAB?
If you overload all of the subclass methods in a hidden methods block I think it will do exactly what you're looking for.
I'm not sure which versions of Matlab this works in, but it definitely works for me in R2012b.
The exception is isvalid as it is Sealed so you can't override it in a handle subclass.
classdef handle_light < handle
methods(Hidden)
function lh = addlistener(varargin)
lh = addlistener#handle(varargin{:});
end
function notify(varargin)
notify#handle(varargin{:});
end
function delete(varargin)
delete#handle(varargin{:});
end
function Hmatch = findobj(varargin)
Hmatch = findobj#handle(varargin{:});
end
function p = findprop(varargin)
p = findprop#handle(varargin{:});
end
function TF = eq(varargin)
TF = eq#handle(varargin{:});
end
function TF = ne(varargin)
TF = ne#handle(varargin{:});
end
function TF = lt(varargin)
TF = lt#handle(varargin{:});
end
function TF = le(varargin)
TF = le#handle(varargin{:});
end
function TF = gt(varargin)
TF = gt#handle(varargin{:});
end
function TF = ge(varargin)
TF = ge#handle(varargin{:});
end
function TF = isvalid(varargin)
TF = isvalid#handle(varargin{:});
end
end
end
If you save the above class to handle_light.m and then type methods handle_light in the command window you will get the following result:
Methods for class handle_light:
handle_light isvalid
The Test class then becomes:
classdef Test < handle_light
methods
function myFunction(obj)
end
end
end
Doing it in this way means that you don't need to put the overloads in the Test class which keeps things neater.
There is a solution here, including sample code.
In short, what you need to do is to overload Matlab's built-in function methods, so that when it is called on your class, it removes the methods of handle from the output. Make sure it works on everything else, though so that you don't mess up your user's other code. If you don't use the #foldername variant to store your class, you could put it into a private directory, for example.
Not a full solution, but if you do methods(T, '-full'), then it at least tells you which methods are inherited from handle, so you know what to ignore.
Just get the functions from the inherited class and cancel them out with the ones from the main class using setdiff.
mH = methods('handle');
m = methods('MyClass');
m = setdiff(m,mH);