Matlab: Class destructor not called during clear? - oop

In Matlab I have a class
classdef myClass
properties
% some properties here...
end
methods ( Access = 'public' )
function obj = myClass()
% constructor...
end
function obj = delete( obj )
% suppose to be destructor...
fprintf(1, 'delete\n');
end
end % public methods
end
What is the default behavior of Matlab when I clear a variable of type myClass?
For example:
>> m = myClass();
>> clear m
I would expect Matlab to call the destructor of m at this stage, but it seems like it doesn't!!
My questions:
How can I force a call to the destructor when clearing a variable?
Is this default behavior of Matlab's makes any sense? Isn't it more logical to call the destructor when clearing a variable?
Is it possible that Matlab's classes do not have a detructor method (that is, there is no default method to be called when the class is destroyed)? Or am I missing something?
Is it possible that only classes derived from handle have a destructor (the delete method)?
Thanks!
EDIT : following Jonas' answer, a brief summary:
Matlab has two types of classes: value classes (the default) and handle classes (derived from handle super class). Value classes tends to provide better performance, however, they do not have a destructor functionality.
handle classes do have a destructor function: delete that is called when the class is destroyed. See this question from more details on handle class destructors.
If one wishes to have a destructor-like functionality for value classes, Jona's answer proposes a method utilizing onCleanup functionality.
Thanks for the good answer and the insightful comments!

Delete is only defined as class destructor for handle classes, not value classes (so the answer to Q4 is "yes", see the previous link to the documentation). Value classes work very much like standard Matlab arrays, in that they're passed by value rather than by reference, and in that many of the internals, such as destructors, are hidden from the user. In exchange, they're usually faster (see for example this SO question).
Consequently, I suggest to use the onCleanup functionality if you want to have a delete method being called (note that delete(m) will not actually delete anything, so you may want to make that a private method).
classdef myTestClass
properties
% some properties here...
end
properties (Hidden)
cleanup
end
methods ( Access = 'public' )
function obj = myTestClass()
% constructor...
obj.cleanup = onCleanup(#()delete(obj));
end
end
methods ( Access = 'private' )
%# I suggest hiding the delete method, since it does not
%# actually delete anything
function obj = delete( obj )
fprintf(1, 'delete\n');
end
end % public methods
end

Related

MATLAB OOP: Communication between objects of different subclasses

I am at the beginning of a bigger project, where I have to rewrite existing MATLAB script code. I was asked to use MATLAB's object oriented programming support to get a more flexible and robust program.
I got to a point, where I wondered how to let objects of different subclasses communicate or better: what is the best or most elegant/efficient/user friendly way to do that.
Example:
Superclass A (handle class):
classdef A < handle
properties
myvar
end
methods (Access = protected)
function calc_myvar(obj)
%calculate myvar with some code
obj.myvar=...;
end
end
end
Subclass B:
classdef B < A
properties
subclassvar
end
methods (Access = protected)
function calc_subclassvar(obj)
%calculate subclassvar with some code
%needs myvar of an object of class C
%C.myvar
obj.subclassvar=...;
end
end
end
Subclass C:
classdef C < A
properties
%some other properties
end
methods
%some other methods
end
end
So subclass B needs a variable of subclass C that is defined in A. At the moment I always pass an object of C as additional input parameter to the function. Additionally I don't know if C.myvar already has a value.
Current implementation:
function calc_subclassvar(obj,C)
if isempty(C.myvar)
C.calc_myvar;
end
obj.subclassvar = do_something_with_C.myvar;
end
Is there another, better way? I read of overloading the get function, so I don't have to check everytime if the variable exists? And I read about events and listeners but couldn't get it to work satisfactorily. For example if I want to add a listener to C it has to know from which specific object of A the event is sent. Or is there a way that C just listens for any object of A?
Maybe you know another way. It's kind of confusing. =)
I think you are over complicating the problem a bit. Either that, or I do not completely understand what you are asking for.
First of all, you are not using any constructors. I would normally use those to pass references to objects needed in a given class at instance-time. Secondly, you write that you don't know if C has been initialized when you need it in B. I see that as a lack of structure in your program, so if a part of your restructuring task is to make the program more robust, this would be a good place to start. Unless you have really good reasons against it, you should be able to tell in which order different objects are being initialized. Using constructors as explained above forces you to consider this, as you can't instance C without an instance of B in your example.
Below are my version of B and C. I excluded A as the need for inheritance is not really concerned with this problem.
Class C:
classdef C < handle
properties
some_const = pi;
end
methods
%some other methods
end
end
Class B:
classdef B < handle
properties
C_handle
end
methods (Access = public)
function obj = B(C_handle)
obj.C_handle = C_handle;
end
function disp_c_var(obj)
disp(obj.C_handle.some_const)
end
end
end
Use of the classes:
c_inst = C();
b_inst = B(c_inst);
b_inst.disp_c_var();
Now, all subsequent uses of b_inst already have a reference to c_inst, so it wont have to be passed again.

Overriding superclass methods and access modifiers in MATLAB

Consider the following simple class hierarchy:
A.m
classdef A < handle
methods (Access = protected) %# protected vs. private
function foo(obj)
disp('class A')
end
end
end
B.m
classdef B < A
methods (Access = public)
function foo(obj)
disp('class B')
end
end
end
Class B inherits from class A and is supposed to override the protected foo method as public.
If we try to instantiate the derived class, we get the following error:
>> b=B();
Error using B
Method 'foo' in class 'B' uses different access permissions than its superclass 'A'.
The weird thing is if foo was defined as private method in the superclass A, the code works just fine when we invoke the overridden method:
>> clear classes
>> b=B(); b.foo()
class B
So is this a limitation/bug in MATLAB OOP implementation, or is there a good reason behind this behavior? (Code was tested on R2012b)
As a comparison, in Java the rules state that you cannot reduce visibility of a method in the sub-class, but you can increase it, where:
(weakest) private < package < protected < public (strongest)
This appears to be a limitation of Matlab. I've tried all combinations of attributes. Matlab throws errors whenever the attributes are different, except when the method of A is private, in which case the attributes in B don't matter.
In other words, unless the method in A is private, the attributes of the method in A and B have to be the same. I guess this does make sense to some extent, in that TMW say "If a method is visible to the subclass, attributes have to be the same; if a method is not visible to the subclass, the subclasses can do whatever they like".

Multiple class constructor Matlab

Is it possible define more than one class constructor in Matlab? If yes, how?
Each class has one constructor. However ... the constructor can accept any number and type of arguments, including those based on varargin.
So, to provide the option of a default third argument in Java you could write something like this (examples based on java documentation):
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
public Bicycle(int startCadence, int startSpeed) {
gear = 1;
cadence = startCadence;
speed = startSpeed;
}
In Matlab you could write
classdef Bicycle < handle
properties (Access=public)
gear
cadence
speed
end
methods (Access = public)
function self = Bicycle(varargin)
if nargin>2
self.gear = varargin{3};
else
self.gear = 1;
end
self.cadence = varargin{1};
self.speed = varargin{2};
end
end
end
The answer of Pursuit works, but a user not familiar to the function can't see how many arguments are needed or what they are for. I would recommend this:
methods (Access = public)
function self = Bicycle(startCadence, startSpeed, startGear)
if nargin>2
self.gear = startGear;
else
self.gear = 1;
end
self.cadence = startCadence;
self.speed = startSpeed;
end
end
If you now type "Bicycle(" and wait you can see at least the three arguments. The second possibility is not shown though. It seems possible (e.g. for plot) but I don't know how to do this.
Each class has only one constructor, and each .m-file can only contain one class definition.
If you want to have a class with slight differences depending on input, you can use properties that define switches that are recognized by the class methods. If you want to have very different classes depending on input, you can create a generateClass-function that will call either one or the other class defined in different files. Of course, if these different classes have lots of common methods and properties, you can create both as subclasses to a common superclass.
No. The constructors in OOP matlab are very restricted compared to other languages. It is not explicitly stated in the documentation AFAIK that you can have multiple constructors, but it refers to the constructor of a class in the singular throughout the documentation.
https://www.mathworks.com/help/matlab/matlab_oop/class-constructor-methods.html

How to call appropriate subclass constructor inside base class constructor in MATLAB

I'm trying to use single inheritance in Matlab, and to write a base class constructor that allows the creation of arrays of objects, including empty arrays, and which is inherited by subclasses. I can't work out how to do it without using some incredibly clunky code. There must be a better way.
In this toy example, my base class is called MyBaseClass, and my subclass is called MySubClass. Each can be constructed with a single numeric argument, or no arguments (in which case NaN is assumed). In the toy example my SubClass is trivial and doesn't extend the behavior of MyBaseClass in any way, but obviously in practice it would do more stuff.
I want to be able to call the constructor of each as follows:
obj = MyBaseClass; % default constructor of 'NaN-like' object
obj = MyBaseClass([]); % create an empty 0x0 array of type MyBaseClass
obj = MyBaseClass(1); % create a 1x1 array of MyBaseClass with value 1
obj = MyBaseClass([1 2; 3 4]) % create a 2x2 array of MyBaseClass with values 1, 2, 3, 4.
And the same four calls for MySubClass.
The solution I have found needs to call eval(class(obj)) in order to recover the subclass name and construct code in strings to call while in the base class constructor. This seems clunky and bad. (And it's somewhat surprising to me that it's possible, but it is.) I guess I could duplicate more logic between the MyBaseClass and MySubClass constructors, but that also seems clunky and bad, and misses the point of inheritance. Is there a better way?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MyBaseClass.m
classdef MyBaseClass
properties
data = NaN
end
methods
% constructor
function obj = MyBaseClass(varargin)
if nargin == 0
% Handle the no-argument case
return
end
arg = varargin{1};
% assume arg is a numeric array
if isempty(arg)
% Handle the case ClassName([])
% Can't write this, because of subclasses:
% obj = MyBaseClass.empty(size(arg));
obj = eval([class(obj) '.empty(size(arg))']);
return
end
% arg is an array
% Make obj an array of the correct size by allocating the nth
% element. Need to recurse for the no-argument case of the
% relevant class constructor, which might not be this one.
% Can't write this, because of subclasses
% obj(numel(arg)) = MyBaseClass;
obj(numel(arg)) = eval(class(obj));
% Rest of the constructor - obviously in this toy example,
% could be simplified.
wh = ~isnan(arg);
for i = find(wh(:))'
obj(i).data = arg(i);
end
% And reshape to the size of the original
obj = reshape(obj, size(arg));
end
end
end
% end of MyBaseClass.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MySubClass.m
classdef MySubClass < MyBaseClass
methods
function obj = MySubClass(varargin)
obj = obj#MyBaseClass(varargin{:});
end
end
end
% end of MySubClass.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Your solution is functional and embraces some loose MATLAB typing to achieve what you want. However, getting clean and structured OOP is probably going to require losing some of the functionality you want. At the same time, the best option for avoiding code duplication is templated/generic container classes but these are not supported in MATLAB at this time.
Your code mirrors the MATLAB documentation on Building Arrays in the Constructor and relies on MATLAB being a loosely typed language that enabled you to convert an object into an array of objects without problem. Exploiting this powerful and flexible feature of MATLAB does introduce some organizational issues and may undermine your efforts at clean, object oriented code.
Problems begin because the MyBaseClass constructor is not a true constructor for MyBaseClass.
Wikipedia says:
"In object-oriented programming, a constructor (sometimes shortened to ctor) in a class is a special type of subroutine called at the creation of an object. It prepares the new object for use, often accepting parameters which the constructor uses to set any member variables required when the object is first created. It is called a constructor because it constructs the values of data members of the class."
Notice that the MyBaseClass constructor is not constructing values for the object members. Instead, it is a function that sets the object equal to an array of objects of type MyBaseClass and tries to set their data members to some value. You can see where the obj is destroyed at set to an array here:
obj(numel(arg)) = eval(class(obj));
This behavior is especially unhelpful when you derive MySubClass from MyBaseClass because MyBaseClass isn’t supposed to assign a new object to the variable obj----MySubClass has already created the new object in obj and is simply asking MyBaseClass to construct the portion of the existing object in obj that MyBaseClass knows the details for.
Some clarity might be gained by noting that when you enter the constructor for both MyBaseClass and MySubClass the variable obj is already populated with a perfectly good instance of the class. Good OOP practice would have you keep this original instance, use it in the base class constructor, and only act to populate its members in the constructor----not to overwrite the object entirely with something new.
My conclusion would be to not assign obj to be an array inside of MyBaseClass. Instead, I would recommend creating a class MyBaseClassArray that creates an array of MyBaseClass objects.
Unfortunately, you would also need to create a duplicate class MySubClassArray that creates an array of MySubClass objects. Languages like C++ and Java get around this code duplication issue with templates and generics, respectively but MATLAB does not currently support any form of templates (http://www.mathworks.com/help/techdoc/matlab_oop/brqzfut-1.html). Without templates there is no good way to avoid code duplication.
You could try and avoid some duplication by creating a generic CreateClassArray function that takes the string name of a class to create and the constructor arguments to use for each object---but now we are coming back to code that looks like your original. The only difference is now we have a clear division between the array class and the individual objects. The truth is that although MATLAB does not support templates, its flexible classes and typing system allow you use eval() like you have to change code and overwrite obj at will and create code that acts generically across classes. The cost? Readability, speed, and the uncomfortable feeling you got when you saw your base class constructing the subclass.
In short, you used MATLAB’s flexibility to overwrite the obj in the constructor with an array to avoid creating a separate container class for MyBaseClass. You then used eval to make up for not having a template feature in MATLAB that would allow you to reuse your array creation code all types. In the end, your solution is functional, reduces code duplication, but does require some unnatural behavior from your classes. It’s just a trade you have to make.

MATLAB - obtain the object a property belongs to?

Suppose I have a myClass < handle with property A. If I create an instance of myClass, say myObj, and pass myObj.A to a function, say function myFunc(val), is it possible within myFunc to see that the val passed to it is a property of myObj?
EDIT: For context:
I'm writing an API (in a sense) to interface with Arduino hardware for my research lab. The overarching class is called Vehicle, with properties PinManager < handle, TelemCollector < handle, and various Device < handles. It also has methods to do things like runMotor(), getAltitude(), etc. I have a method TelemCollector.telemFetch() which is the callback for a timer event; I would like TelemCollector.telemFetch() to be able to access Vehicle methods (namely getAltitude()); naively I would just make Vehicle a property of TelemCollector to access those methods. I was hoping to not have to do this.
EDIT2: Sample code snippet of what I'm trying to accomplish:
classdef Vehicle < handle
properties
PinManager
TelemCollector
Devices
end
methods
function obj = Vehicle(PM, TC, D)
obj.TC = TelemCollector();
obj.PM = PinManager();
obj.Devices = D();
end
function val = getAltitude(obj)
%# read altitude from a connected Device
end
function val = getSpeed(obj)
%# read speed from connected Device
end
end
end
classdef TelemCollector < handle
properties
%# ...
end
methods
function fetchTelem(obj)
%# do getAltitude(), getSpeed(), etc, here.. but I want to access
%# Vehicle.getAltitude() and Vehicle.getSpeed() somehow!
end
end
end
For all I know, no.
For example if myObj.A is a double, myFunc will just be passed the value it contains and there will be no reference to the object. If you were calling myFunc(somevariable) where somevariable was really the name of a variable and not an expression, then calling inputname(1) inside of myFunc would give you the string 'somevariable', but since you are referring to a property of a class, this is too complicated for MATLAB and inputname(1) just returns '' (tested with MATLAB R2011a).
Update: Why do you need to know this anyhow? If your interfaces are cleanly designed, you should probably not have to do this kind of thing. Or are you trying to work around someone else's bug/bad design? Depending on your application you could think of some kind of very dirty hack involving dbstack, trying to find out which m-file called your function, read the appropriate line of code from the .m file, parse it and then access the object using evalin('caller',...) ... but I doubt that's a good idea ;-).
Edit in response to context you provided:
Can't you just redefine your Timer callback to hand over the "Vehicle" object as well? i.e.
set(yourtimer_handle,'TimerFcn',{#fetchTelem,vehicle_handle});
means that whenever the callback timer calls the function TelemCollector.fetchTelem(), it hands over vehicle_handle as a third argument as described in the docu. This works in conjunction with a changed function head
function fetchTelem(obj, event, vehicle_handle)
where you can replace event by ~ in newer MATLAB versions if you don't need it.
Could that work?
fetchTelem can't call methods of an object that it doesn't have a reference to. So, regardless, you need to provide your TelemCollector object with the Vehicle handle.
Personally, I think the association between Vehicle and TelemCollector should be in the opposite direction. I would prefer something that looked more like:
V = Vehicle(PM, D);
TC = TelemCollector(V);
Although it really depends on how you expect to use the classes.
I agree with #Jonas Heidelberg: if it's this difficult, then it's probably the wrong interface.