Modifying an immutable/protected variable of a subclass in a superclass method - matlab

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.

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.

Problem with implementing abstract property in Matlab

In Matlab (2017b) I'm trying to implement a superclass with a yet undefined abstract property.
classdef Class_Test1
properties (Abstract=true)
obj
end
end
Subclasses should then implement this property and restrict it to a certain class, e.g.:
classdef Class_Test2 < Class_Test1
properties
obj#double = 123;
end
end
a = Class_Test2; now throws an error:
The property 'obj' restriction defined in class 'Class_Test2' must match
the property definition in base class 'Class_Test1'.
Is there no way to specify the class / type of obj in the implementation of the abstract class or am I missing something?
In the end I would like obj to be abstract in Class_Test1 to implement several subclasses, which will hold objects of different classes in obj.
Any help appreciated ...
MATLAB classes are weird... or in any case very different from what you expect from a class if you've learnt about classes in any other programming language.
One aspect of MATLAB is that it's an interpreted language. Stuff is evaluated when executed, not when compiled. So code doesn't always need to make sense.
So, we can solve your issue like this:
classdef (Abstract) foo
methods
function c = getclass(in)
c = class(in.obj);
end
end
end
The function foo.getclass seems to not make sense, since foo doesn't have a property obj. But because foo is abstract, we're never going to have an object of class foo on which we'll call the getclass method. Whenever getclass is called, it'll be a derived class. So, if we want to use this getclass method, we need to make sure that the derived class has a property obj:
classdef foo_uint8 < foo
properties
obj#uint8 = uint8(1);
end
end
It is now possible to call foo_uint8.getclass:
>> a = foo_uint8;
>> a.getclass
ans =
'uint8'
OK, so after looking into this further it seems that this is a deliberate limitation based on the design of Matlab. I'm not too familiar with OOP in other languages but would be interested to learn if this is an general OOP fundamental or rather Matlab specific.
As a workaround I have come up with the following solution:
classdef (Abstract) Class_Test1 < handle
properties
Obj
end
properties (Abstract = true, Constant)
ObjClass#char
end
methods
function set.Obj(obj_in,in)
if isa(in, obj.ObjClass)
obj_in.Obj = in;
end
end
end
end
... and the implementation ...
classdef Class_Test2 < Class_Test1
properties (Constant)
ObjClass#char = 'double'; % Define the allowed class here ...
end
end
I would still be interested to learn about other possible solutions.

How to check if a class has a specific base class in Matlab

I define in Matlab a class that's a subclass of another one, like this:
classdef SpecificLimit < BaseLimit
% Private properties section
properties (SetAccess = private, GetAccess = private)
options;
end
% Public section
methods (Access = public)
% ...
end
end
Now I've a variable named r and I want to check if this variable is a class instance that has BaseLimit as base class (I've a lot of them). Is there an easy way to do that? I've read about meta.class but I didn't find a way to perform this check.
I'm using Matlab r2014a.
You should use isa which determines if an object is either a BaseLimit instance or is derived from BaseLimit.
isa(r, 'BaseLimit')
You can use the function superclasses
Something like:
any ( strcmp ( superclasses ( 'SpecificLimit' ), 'BaseLimit' ) )

object oriented MATLAB: static method from parent can't set protected property from child

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

Passing objects to other objects in MATLAB

I'm starting out with object-oriented programming in MATLAB, and I'm confused on how to best pass objects to other objects, as MATLAB doesn't feature static type definitions.
I have three different classes, all of which include some constants. Now, I want to use the constants defined in two of the classes in the methods of the third class - how should I do this? The classes are in no hierarchy.
So, I'm looking for something like #include in C++.
Problem illustrated below. How to write "*Object1" and "*Object2" references to access const1 and const2?
classdef Object1
properties (Constant)
const1 = 100;
end
methods
function Obj1 = Object1()
end
end
classdef Object2
properties (Constant)
const2 = 200;
end
methods
function Obj2 = Object2()
end
end
classdef Object3
properties (Immutable)
property3
end
methods
function Obj3 = Object3()
Obj3.property3 = *Object1.const1 + *Object2.const2;
end
end
Just remove the asterisks, and I think you have what you need.
There are a couple of other syntax errors in your code (replace Immutable with SetAccess = immutable, and add missing ends to the classdefs), but once I made those changes, I get:
a = Object3
a =
Object3
Properties:
property3: 300
Methods
In general, to reference a Constant property from another class, just prefix the property with the class name (and possibly package name, if the classes are in a package).