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
Related
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.
I have the following class in MATALB.
classdef MyClass
properties
a;
end
methods
function foo(obj)
obj.a = 1;
end
end
end
Now, I do this.
mc = MyClass;
mc.foo();
Now we have this.
mc.a == []
This is something I don't understand. I was expecting
mc.a == [1]
Why hasn't the function foo changed the state of the object?
I am sorry if this is a very basic question. I am used to languages like Java and C#, where the semantics is clearly according to what I'm expecting.
I've discovered that if I do the following, it works are expected.
classdef MyClass < handle
But how to get the desired behavior with a value class in MATLAB (i.e. not a handle class)?
Since a value class is passed by value, not by reference, you need foo to return the updated object:
classdef MyClass
properties
a;
end
methods
function obj = foo(obj)
obj.a = 1;
end
end
end
Then
mc = MyClass;
mc = mc.foo();
This is why I only use handle classes.
In Matlab, I can define a class as such:
classdef klass < handle
properties(Dependent)
prop
end
end
Matlab is perfectly happy instantiating an object of this class, even without defining a getter for prop. It only fails when I try to access it (understandably). I'd like to set the GetMethod dynamically based upon the property's name.
Unfortunately, even when the property is Dependent, the meta.property field for GetMethod is still read-only. And while inheriting from dynamicprops could allow adding a property and programmatically setting its GetMethod in every instance, I don't believe it could be used to change an existing property. I may have to go this route, but as prop must exist for every object I'd prefer to simply set the getter on a class-by-class basis. Is such a thing possible?
An alternative solution could be through some sort of catch-all method. In other languages, this could be accomplished through a Ruby-like method_missing or a PHP-like __get(). But as far as I know there's no (documented or otherwise) analog in Matlab.
(My use case: this class gets inherited by many user-defined subclasses, and all their dependent properties are accessed in a similar way, only changing based on the property name. Instead of asking users to write get.* methods wrapping a call to the common code for each and every one of their dependent properties, I'd like to set them all dynamically with anonymous function pointers containing the necessary metadata).
Here is my proposal: create a method in the superclass called add_dyn_prop. This method is to be called in the subclasses instead of creating a dependent property the usual way.
The idea is that the superclass inherit from dynamicprops and use addprop to add a new property, and set its accessor methods manually based on its name.
classdef klass < dynamicprops
methods (Access = protected)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
% NOTE: this has to be a simple function_handle (#fun), not
% an anonymous function (#()..) to avoid infinite recursion
p.GetMethod = #get_method;
p.SetMethod = #set_method;
% nested getter/setter functions with closure
function set_method(obj, val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
now in the subclass, instead of defining a dependent property the usual way, we use this new inherited function in the constructor to define a dynamic property:
classdef subklass < klass
%properties (Dependent, SetAccess = private)
% name
%end
%methods
% function val = get.name(obj)
% val = 'Amro';
% end
%end
methods
function obj = subklass()
% call superclass constructor
obj = obj#klass();
% define new properties
add_dyn_prop(obj, 'name', 'Amro');
add_dyn_prop(obj, 'age', [], false)
end
end
end
The output:
>> o = subklass
o =
subklass with properties:
age: []
name: 'Amro'
>> o.age = 10
o =
subklass with properties:
age: 10
name: 'Amro'
>> o.name = 'xxx'
You cannot set the read-only property 'name' of subklass.
Of course now you can customize the getter method based on the property name as you initially intended.
EDIT:
Based on the comments, please find below a slight variation of the same technique discussed above.
The idea is to require the subclass to create a property (defined as abstract in the superclass) containing the names of the desired dynamic properties to be created. The constructor of the superclass would then create the specified dynamic properties, setting their accessor methods to generic functions (which could customize their behavior based on the property name as you requested). I am reusing the same add_dyn_prop function I mentioned before.
In the subclass, we are simply required to implement the inherited abstract dynamic_props property, initialized with a list of names (or {} if you dont want to create any dynamic property). For example we write:
classdef subklass < klass
properties (Access = protected)
dynamic_props = {'name', 'age'}
end
methods
function obj = subklass()
obj = obj#klass();
end
end
end
The superclass is similar to what we had before before, only now is it its responsibility to call the add_dyn_prop in its constructor for each of the property names:
classdef klass < dynamicprops % ConstructOnLoad
properties (Abstract, Access = protected)
dynamic_props
end
methods
function obj = klass()
assert(iscellstr(obj.dynamic_props), ...
'"dynamic_props" must be a cell array of strings.');
for i=1:numel(obj.dynamic_props)
obj.add_dyn_prop(obj.dynamic_props{i}, [], false);
end
end
end
methods (Access = private)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
%p.Transient = true;
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
p.GetMethod = #get_method;
p.SetMethod = #set_method;
% nested getter/setter functions with closure
function set_method(obj,val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
Note: I did not use ConstructOnLoad class attribute or Transient property attribute, as I am still not sure how they would affect loading the object from a saved MAT-file in regards to dynamic properties.
>> o = subklass
o =
subklass with properties:
age: []
name: []
>> o.name = 'Amro'; o.age = 99
o =
subklass with properties:
age: 99
name: 'Amro'
Check if this is what you want. The problem is that the user will need to get the properties using (), which may be quite boring, but anyway, I think this way you can change the variables. You can't change them directly on the class, but you can change the objects property values on demand. It doesn't need to change the values on the constructor, you can do that using another function that will be inherited by the classes.
klass1.m
classdef(InferiorClasses = {?klass2}) klass < handle
methods
function self = klass
selfMeta = metaclass(self);
names = {selfMeta.PropertyList.Name};
for name = names
switch name{1}
case 'prop_child_1'
self.(name{1}) = #newGetChild1PropFcn;
case 'prop_child_2'
self.(name{1}) = #newGetChild2PropFcn;
end
end
end
end
methods(Static)
function out = prop
out = #defaultGetPropFcn;
end
end
end
function out = defaultGetPropFcn
out = 'defaultGetPropFcn';
end
function out = newGetChild1PropFcn
out = 'newGetChild1PropFcn';
end
function out = newGetChild2PropFcn
out = 'newGetChild2PropFcn';
end
klass2.m
classdef klass2 < klass
properties
prop_child_1 = #defaultGetChildPropFcn1
prop_child_2 = #defaultGetChildPropFcn2
end
methods
function self = klass2
self = self#klass;
end
end
end
function out = defaultGetChildPropFcn1
out = 'defaultGetChildPropFcn1';
end
function out = defaultGetChildPropFcn2
out = 'defaultGetChildPropFcn2';
end
Output:
a = klass2
b=a.prop_child_1()
b =
newGetChild1PropFcn
I am trying to figure out the best way to create an alternative to the C++ template or the Java generic objects. I have wanted to do this several times in the past for several different reasons, however right now what I want to do is related to creating the saveobj and loadobj functions for several related classes. The idea is that I want to have a generic set of routines to create a default struct and then manipulate that a little bit farther to get the structs the way I want them.
I cannot simply use an external function because I need access to all the public (not a problem) and protected (problem) non-transient properties of an object in order to create the loadobj and saveobj.
Then I considered using an abstract interface. However, using an abstract interface leaves me with the same problem; identical, copy an pasted code floating around in all of my object files. So then I thought of using some sort of full blown object combined with multiple inheritance (Most of my objects are already inheriting from a basic concretion of interfaces). I thought using a superclass would allow me to expose the subclass protected properties, but it doesn't seem to work that way. Any suggestions?
Here is a sample of the multiple inheritance approach (the closest thing I have so far) for the save obj approach.
Serializer.m
% Serializer.m
classdef Serializer
methods
function [saveObj] = saveobj( obj )
% Get metadata about the Object
meta = metaclass( obj );
meta = meta.PropertyList;
for p = meta'
if p.Transient | p.Dependent
continue; % Only serialize the correct fields
end
saveobj.(p.Name) = { obj.(p.Name) }; % Serialize
end % for ( property )
end % function ( saveobj )
end % methods
end % classdef ( Serializer )
TestSerializerA.m
% TestSerializerA.m
classdef TestSerializerA < Serializer
properties
PropA = 'a';
end % properties ( public )
properties( Access = protected )
HiddenA = 'ha'
end % properties ( protected )
end % classdef ( TestSerializerA )
TestSerializerB.m
% TestSerializerB.m
classdef TestSerializerB < TestSerializerA & Serializer
properties
PropB = 'b'
end
properties( Access = protected )
HiddenB = 'hb';
end % properties ( protected )
end % classdef ( TestSerializerB )
Solution
You can accomplish what you are looking to do by using Access lists. You can allow the Serializer class access to any protected/private class members you would like to be serialized. This allows each class to determine on its own which of its members are serialized. Since you are allowing access to Serializer, you do not want to inherit from it. If you do, all classes in the heirarchy will have access to those members. Here is the rewritten Serializer class:
classdef Serializer
methods
function SerializedObj = serialize(~, Obj)
% Get metadata about the Object
meta = metaclass(Obj);
meta = meta.PropertyList;
for p = meta' %'
if p.Transient || p.Dependent
continue; % Only serialize the correct fields
end
try
SerializedObj.(p.Name) = { Obj.(p.Name) }; % Serialize
catch Me
% the class has chosen not to allow this property to be
% serialized. decide how to handle it.
if ~strcmp(Me.identifier, 'MATLAB:class:GetProhibited')
Me.rethrow()
end
end
end
end
end
end
Note that you can decide how you want to handle the access restrictions. In the above example, I do nothing. But you could issue a warning, throw an error, etc... .
Now, instead of inheriting from Serializer, create an abstract Serializable class, which will enable serialization.
classdef (Abstract) Serializable
properties (Access = private)
Serializer_ = Serializer()
end
methods
function savedObj = saveobj(This)
savedObj = This.Serializer_.serialize(This);
end
end
end
Now any class you wish to enable serialization on will additionally inherit from Serializable. You can specify which protected/private members the Serializer has access to.
Examples
The following class has two serializable properties, and one hidden (not serializable) property.
classdef TestSerializerA < Serializable
properties
PropA = 'a';
end
properties( Access = {?TestSerializerA, ?Serializer} )
% This property is protected and serializable
SerializableA = 'sa'
end
properties (Access = private)
% This property is private and not serializable
HiddenA = 'ha';
end
end
This is the result from MATLAB:
>> Test = TestSerializerA
Test =
TestSerializerA with properties:
PropA: 'a'
>> b = saveobj(Test)
b =
PropA: {'a'}
SerializableA: {'sa'}
The next example inherits from TestSerializerA, and has an additional two serializable properties, and one hidden property.
classdef TestSerializerB < TestSerializerA & Serializable
properties
PropB = 'b';
end
properties (Access = {?TestSerializerB, ?Serializer})
% This property is protected and serializable.
SerializableB = 'sb';
end
properties (Access = protected)
% This property is protected and not serializable.
HiddenPropB = 'hb';
end
end
Note here that re-inheriting from Serializable is unnecessary, but makes for easier to read code.
Lastly, the result from MATLAB:
>> Test = TestSerializerB
Test =
TestSerializerB with properties:
PropB: 'b'
PropA: 'a'
>> b = saveobj(Test)
b =
PropB: {'b'}
SerializableB: {'sb'}
PropA: {'a'}
SerializableA: {'sa'}
I hope this helps!
I am trying to create a Matlab Class, where the methods attributes are changed in the Class Constructor. The purpose of this is to hide / make visible some methods, depending on the class input.
For example:
classdef (HandleCompatible) myClass < dynamicprops & handle % & hgsetget
properties (Hidden)
myProp
end
methods (Hidden)
function obj = myClass(input)
%class constructor
%add some dynamic properties
switch input
case 1
%unknown code:
%make myMethod1 visible
case 2
%unknown code:
%make myMethod2 visible
otherwise
%unknown code:
%make myMethod1 visible
%make myMethod2 visible
end
end
end
methods (Hidden)
function myMethod1 (obj, input)
%function...
end
function output = myMethod2(obj, input)
%function...
end
end
end
I tried to use the following:
mco = metaclass(obj);
mlist = mco.MethodList;
mlist(myMethod1Index).Hidden = false;
, but I get the following error:
Setting the 'Hidden' property of the 'meta.method' class is not allowed.
Thank you for your reply.
This could be a solution, if I need to access my methods selectively in the class constructor. Though, I need to use these methods in my program, and to have them visible or not, at tab completion:
%Obj1
myObj1 = myClass (inputs, '-1');
myObj1.myMethod1(arg);
%myObj1.myMethod2 - hidden
%Obj2
myObj2 = myClass (inputs, '1');
%myObj2.myMethod1 - hidden
value1 = myObj2.myMethod2(arg);
%Obj3
myObj3 = myClass (inputs, '0');
myObj3.myMethod1(arg);
value2 = myObj3.myMethod2(arg);
%here i want to be able to access both methods
Maybe it is possible to select the method properties, during class constructor, and change the attributes. But this has to be done without using the metaclass
Why not expose only a factory method and build instances of different classes depending on the input? You can use access qualifiers to lock things down like so:
% a.m
classdef a
properties, a_thing, end
methods ( Access = ?factory )
function obj = a()
end
end
end
% b.m
classdef b
properties, b_thing, end
methods ( Access = ?factory )
function obj = b()
end
end
end
% factory.m
classdef factory
methods ( Static )
function val = build(arg)
if isequal(arg, 'a')
val = a;
else
val = b;
end
end
end
end