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.
Related
Ok, so I have a parent class MOM with a bunch of properties with the SetAccess attribute set to protected. It has a special static method setProperty for setting its properties:
classdef MOM < handle
properties (SetAccess = 'protected')
age;
occupation;
num_kids;
MOMmusthaves ={'age','occupation','num_kids'};
end
methods
function obj = MOM(varargin)
if iscell(varargin{1,1})
varargin =varargin{1,1};
end
inputstrings=varargin(cellfun(#isstring,varargin)); % get strings out of the inputs
if(isempty(setxor(intersect(inputstrings,obj.MOMmusthaves),obj.MOMmusthaves)))
% if all proper inputs are entered, initialize your object
for pp =1:length(obj.MOMmusthaves)
obj.setProperty(obj,varargin,obj.MOMmusthaves{pp});%find each input in the vararagins, and set it
end
else
display('Hey! These inputs are wrong. type help MOM for an example. Make sure you inlcude inputs for all of the following:'); obj.MOMmusthaves
return;
end
end
end
methods (Static)
function setProperty(obj,varargs,xx)
eval(sprintf('obj.%s = varargs{find(strcmp(''%s'',varargs))+1};',xx,xx));
end
end
end
Then I have a child object KID, which has a couple more properties, also SetAccess protected. When I try to use MOM's static method to set a KID property inside the KID's constructor I get an error :(
The error says:
You cannot set the read-only property 'allowance' of KID.
Basically, it seems like KID doesn't think that it can use MOM's static method as its own (so didn't inherit it properly).
MY QUESTION IS:
Is there any way I can make the static method be recycled and usable to KID for its own protected properties?
JUST FYI, here's something like the KID code;
classdef KID < MOM
properties (SetAccess = 'protected')
gender;
allowance;
favoritecandy;
KIDmusthaves ={'gender','allowance','favoritecandy'};
end
methods
function obj = KID(varargin)
obj = obj#MOM(varargin(:)); % Special construct for instantiating the superclass
inputstrings=varargin(cellfun(#isstring,varargin)); % get strings out of the inputs.
if(isempty(setxor(intersect(inputstrings,obj.KIDmusthaves),obj.KIDmusthaves)))
% if all proper inputs are entered, initialize your object
for pp =1:length(obj.KIDmusthaves)
%find each input in the vararagins, and set it
obj.setProperty(obj,varargin,obj.KIDmusthaves{pp});
end
else
display('please use correct input format. Make sure you include inputs for all of the following:');
obj.KIDmusthaves
return;
end
end
end
end
I'm not really sure what the exact source of the error is; although, I think it may be due to the mutation of the handle object being hidden by the eval.
Regardless, if I understand the intended usage of setProperty, I think it may be easiest to write the function in a non-static form using dot notation (similar to dynamic field names with structs):
methods
function [] = setProperty(obj,musthaves,varargin)
keys = varargin(1:2:end);
values = varargin(2:2:end);
for pp =1:length(keys)
key = keys{k};
if any(strcmp(musthaves,key))
obj.(key) = values{pp};
end
end
end
end
where musthaves is any cell array of property strings
You could also have musthaves be a string that indicates the obj property holding the property list:
methods
function [] = setProperty(obj,musthaves,varargin)
keys = varargin(1:2:end);
values = varargin(2:2:end);
for pp =1:length(keys)
key = keys{k};
if any(strcmp(obj.(musthaves),key))
obj.(key) = values{pp};
end
end
end
end
Matlab does not allow to define different methods to define multiple constructors with different list of parameters, for instance this will not work:
classdef MyClass
methods
function [this] = MyClass()
% public constructor
...
end
end
methods (Access = private)
function [this] = MyClass(i)
% private constructor
...
end
end
end
But, as illustrated in above example, it is sometimes useful to have private constructors with particular syntax that cannot be called from public interface.
How would you best handle this situation where you need to define both public and private constructors ?
Checking call stack ???
classdef MyClass
methods
function [this] = MyClass(i)
if (nargin == 0)
% public constructor
...
else
% private constructor
checkCalledFromMyClass();
...
end
end
end
methods(Static=true, Access=Private)
function [] = checkCalledFromMyClass()
... here throw an error if the call stack does not contain reference to `MyClass` methods ...
end
end
end
Define a helper base class ???
% Helper class
classdef MyClassBase
methods (Access = ?MyClass)
function MyClassBase(i)
end
end
end
% Real class
classdef MyClass < MyClassBase
methods
function [this] = MyClass()
this = this#MyClassBase();
end
end
methods (Static)
function [obj] = BuildSpecial()
obj = MyClassBase(42); %%% NB: Here returned object is not of the correct type :( ...
end
end
end
Other solution ???
One sneaky trick that I've used to try and work around this limitation is to use another 'tag' class that can only be constructed by MyClass, and then use that to work out which constructor variant you need. Here's a simple sketch:
classdef MyClass
properties
Info
end
methods
function o = MyClass(varargin)
if nargin == 2 && ...
isa(varargin{1}, 'MyTag') && ...
isnumeric(varargin{2}) && ...
isscalar(varargin{2})
o.Info = sprintf('Private constructor tag: %d', varargin{2});
else
o.Info = sprintf('Public constructor with %d args.', nargin);
end
end
end
methods (Static)
function o = build()
% Call the 'private' constructor
o = MyClass(MyTag(), 3);
end
end
end
And
classdef MyTag
methods (Access = ?MyClass)
function o = MyTag()
end
end
end
Note the Access = ?MyClass specifier which means that only MyClass can build instances of MyTag. There's more about using that sort of method attribute in the doc: http://www.mathworks.com/help/matlab/matlab_oop/method-attributes.html
You can have a constructor that accepts multiple syntaxes by taking advantage of varargin:
classdef MyClass
methods (Access = public)
function obj = MyClass(varargin)
% Do whatever you want with varargin
end
end
end
You might, more typically, have some inputs that are required for all syntaxes, and then some optional inputs as well:
classdef MyClass
methods (Access = public)
function obj = MyClass(reqInput1, reqInput2, varargin)
% Do whatever you want with varargin
end
end
end
If you want to have even more control over how things are constructed, I would have a constructor and then also have some public static methods that called the constructor.
For example, let's say I wanted to be able to construct an object either by supplying parameters directly, or by supplying the name of a config file containing parameters:
classdef MyClass
methods (Access = public)
function obj = MyClass(reqInput1, reqInput2, varargin)
% Do whatever you want with varargin
end
end
methods (Static, Access = public)
function obj = fromFile(filename)
myparams = readmyconfigfile(filename);
obj = MyClass(myparams.reqInput1, myparams.reqInput2, ...);
end
end
end
Then you can create an object either with o = MyClass(inputs) or o = MyClass.fromFile(filename).
If you wanted to allow people to construct only from a config file, you could then make the constructor private. And you could add additional public static methods if you wanted to call the constructor in other ways.
In any case, the main point is that the idiomatic way to have a constructor that accepts multiple syntaxes is to take advantage of varargin.
I'd be tempted to go for a modification on your 1st option, but to modify the constructor to have an undocumented "mode" rather than just any input arg.
In the example below I gave that name **private** but you could have anything you want that the end users are unlikely to stumble across....
To be doubly sure you could still check the stack.
function [this] = MyClass(i)
if (nargin == 0)
% public constructor
else
% private constructor
if ischar ( i ) && strcmp ( i, '**private**' )
this.checkCalledFromMyClass();
else
error ( 'MyClass:Consturctor', 'Error calling MyClass' );
end
end
end
end
I'm trying to modify an immutable/protected property of a subclass, using a superclass method or an external utility function (I'm trying to use this function in the subclass's constructor, of course).
Example (of what I would like to do):
classdef Sup
methods
function self = setProperties(self, varargin)
% This method sets the properties of the object
% the input arguments come in the form 'propname1', val1, 'propname2', val2, ...
...
end % setProperties
end % methods
end % classdef Sup
classdef sub < Sup
properties (SetAccess = immutable)
prop1
prop2
prop3
end % properties
methods
function self = sub(varargin)
% constructor
self = setProperties(self, varargin)
end % sub
end % methods
end % classdef sub
>> SomeObj = sub('prop1', 1, 'prop2', 10, 'prop3', 100);
This code doesn't work, I get the error message 'You cannot set the read-only property 'prop1' of sub.'
I'm OK with setting sub's properties to be protected, but I wouldn't want them to be public. I'm also OK with the idea that setProperties would be an external utility function (not defined in the superclass), but then again, I'm not able to use setProperties in the constructor of sub.
Would appreciate your help on that.
Thank you,
Avihay
If you want to, you could set the SetAccess attribute of sub to ?Sup - in other words saying that they can only be set by the class Sup.
That seems to do what you're directly asking for - however, I should say that this seems like an unusual pattern to be implementing. I wonder whether a better suggestion might be to examine why you're finding a need to do this, and perhaps redesign your class relationships.
Edit:
If what you need is a general method of conveniently setting properties in a constructor, you could try inheriting your class from the built-in class hgsetget. For example,
classdef sub < hgsetget
properties (SetAccess = immutable)
prop1
prop2
prop3
end % properties
methods
function self = sub(varargin)
set(self,varargin{:})
end
end
end
hgsetget gives you built-in methods set (and get) that can be used with the syntax set(obj, 'myprop', myval, 'myprop2', myval2) and similar (like MATLAB Handle Graphics objects, hence the hg in hgsetget).
That might be more convenient for you. Note, though, that hgsetget is itself a subclass of handle, so you will have to be comfortable with your classes being handle objects. However, if you're considering immutable properties, then you're probably OK with that already.
Edit 2:
Another approach, which would work with value objects, might be the following:
classdef sub
properties (SetAccess = immutable)
prop1
prop2
prop3
end % properties
methods
function self = sub(varargin)
% constructor
props = varargin(1:2:end-1);
vals = varargin(2:2:end);
for i = 1:numel(props)
self.(props{i}) = vals{i};
end
end
end
end
Alternatively, you could make use of inputParser within the constructor, to give you a more flexible range of syntaxes.
We have this code in 'Reconstruction the subclass object from a saved struct' from MATLAB OOP documentation.
classdef MySuper
% Superclass definition
properties
X
Y
end
methods
function S = saveobj(obj)
% Save property values in struct
% Return struct for save function to write to MAT-file
S.PointX = obj.X;
S.PointY = obj.Y;
end
function obj = reload(obj,S)
% Method used to assign values from struct to properties
% Called by loadobj and subclass
obj.X = S.PointX;
obj.Y = S.PointY;
end
end
methods (Static)
function obj = loadobj(S)
% Constructs a MySuper object
% loadobj used when a superclass object is saved directly
% Calls reload to assign property values retrived from struct
% loadobj must be Static so it can be called without object
obj = MySuper;
obj = reload(obj,S);
end
end
end
I have a question about obj = MySuper. What is purpose of this line? How we can call MySuper object from this function without insert any object to loadobj function?
You first question is: What is the purpose of the obj = MySuper; line?
The answer is that the obj = MySuper; line initiates the variable obj as an element of the class MySuper. Non-static functions in a class will only run if the first input parameter is an instance of the class, so if obj is not initiated as a MySuper-object, then matlab will look for other functions called reload to run, and if none is found give you an error.
For your second question, I am not 100% sure what you mean. But I hope one of the following points will answer your question:
If you want to make a function that relates to a class, but not to a specific instance of the class, you can make a static function, these can take any input (also (if you want it that way) no input at all) - that is they don't need to have a first input parameter of the specific class.
To run a static function, use the class name followed by a dot and then the function name, so here you would type MySuper.loadobj(S) to run the function with the parameter S.
I would suggest that you try this out with the given example to better get to know the way oop works in matlab, you may for example try:
S.PointX = 1;
S.PointY = 2;
obj = MySuper.loadobj(S)
I hope this answers your questions.
I come from a Java background. I am having issues with classes in Matlab particularly getters and setters. getting a message saying conflict between handle and value class I'm a little lost with what to do so any help for lack of a better word will be helpful.
classdef Person
properties(Access = private)
name;
age;
end
methods
% class constructor
function obj = Person(age,name)
obj.age = age;
obj.name = name;
end
%getters
function name = get.name(obj)
end
function age = get.age(obj)
end
%setters
function value = set.name(obj,name)
end
function value = set.age(obj,age)
end
end
end
Implementation
Since your class is currently a subclass of the default Value class, your setters need to return the modified object:
function obj = set.name(obj,name)
end
function obj = set.age(obj,age)
end
From the documention: "If you pass [a value class] to a function, the function must return the modified object." And in particular: "In value classes, methods ... that modify the object must return a modified object to copy over the existing object variable".
Handle classes (classdef Person < handle) do not need to return the modified object (like returning void):
function [] = set.name(obj,name)
end
function [] = set.age(obj,age)
end
Value vs. Handle
Going a bit deeper, the difference between a Value class and a Handle class lies mostly in assignment:
Assigning a Value class instance to a variable creates a copy of that class.
Assigning a Handle class instance to a variable create a reference (alias) to that instance.
The Mathworks has a good rundown on this topic.
To paraphrase their illustration, the behavior of a Value class is
% p is an instance of Polynomial
p = Polynomial();
% p2 is also an instance of Polynomial with p's state at assignment
p2 = p;
and of a Handle class is
% db is an instance of Database
db = Database();
% db2 is a reference to the db instance
db2 = db;
Quick'n Dirty from the Java perspective:
- "handle" classes are what your mind is set to. proper object instances with pointers to them. use them.
- "value" classes are always returning a full clone of whatever object (which has been modified by what you just did, e.g. setting a name).
the reason they have both in Matlab is that in Matlab you would expect the "value" behaviour natively. Imagine you have a matrix A = [1 2; 3 4], then assign that via B = A. if you now set B(1) = -1 you'd hope that A(1) is still 1, right? this is because matlab keeps track of "copies" and truly creates them as you modify different variables initially set to the same matrix. in OOP you'd have A(1)=-1 now as everythings an object reference.
furthermore, "native" matlab routines dont have a "this/self/me" variable that contains the instance reference to access from within functions. instead, the convention is that the class instance will be prepended to the function's argument list.
so for a function call myclass.mymethod(arg1,arg1), the declaration must be
function mymethod(this, arg1, arg2)
% Note that the name you choose for "this" is arbitrary!
end
mind you, this is the java-perspective (and also my favourite one), the above function call is equivalent to mymethod(myclass,arg1,arg1). this is more native to matlab-style, but somehow makes it harder to see you're calling an objects method.
now, regarding setters/getters: for handle classes, everything feels java-ish now:
classdef MyClass < handle
properties
MyProp;
end
methods
function set.MyProp(this, value) %Note: setMyProp is also valid!
... % do checks etc, trigger calls,
this.MyProp = value;
end
function value = get.MyProp(this)
... % notify, update, triggers etc
value = this.MyProp;
end
end
Of course it goes without saying that you dont need to define a getter if you just want to return the value, i.e. myclassinstance.MyProp will work without any just as well.
Finally, getters/setters for value classes are something that [never encountered me/i never needed] in my 7 years of matlab oop, so my advise would be to go with handle classes and enjoy happy matlab coding :-)
otherwise, the above explanation & official matlab docs is doing the job for value class getter/setters.