How do I call an object's destructor when one of its methods is used as a callback for its own property? - matlab

I'm trying to write a class that wraps around a serial port to read a sensor:
classdef sensor < handle
properties
Value
s
end
methods
function obj = sensor(port)
obj.s = serial(port);
obj.s.BytesAvailableFcn = #(o,e) obj.getData;
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try
fclose(obj.s);
delete(obj.s);
end
end
function getData(obj)
obj.Value = fscanf(obj.s, '%d');
end
end
end
When I try to clear the workspace, the destructor never gets called:
>> foo = sensor('COM1');
>> clear foo % should disp() something!
Based on my previous experiences, there must still be a reference to foo. Turns out this is embedded in the serial port foo.s:
>> ports = instrfindall;
>> ports.BytesAvailableFcn
ans =
#(o,e)obj.getData
Once I clear out the BytesAvailableFcn, i.e.,
>> ports.BytesAvailableFcn = '';
and then clear all, I get my called destructor displayed.
How can I break this circular reference and get my destructor to get called? If the destructor doesn't get called, the serial port stays bound.

The problem is not quite that you have a circular reference; MATLAB should in theory catch those. The issue is that the circular reference goes via Java, and MATLAB can't catch it.
In more detail - your serial object contains a Java object internally, which is the real thing that captures the connection to the serial port. When you set its callback, MATLAB sets the callback of the underlying Java object. If the callback is to a method of an object that contains the serial object as a property, then you have a circular reference that goes via the underlying Java object. When you call clear, MATLAB checks for circular references, and if they were all in only MATLAB it would catch them, and call the destructor - but it doesn't catch them as it goes via Java.
One solution is to explicitly call the destructor, and perhaps that's not too much trouble.
Another workaround might be to simply not have the callback as a method of the class - perhaps it could just be a regular function, as it doesn't really seem to need any information from the main object itself other than the reference to the serial object. If you would prefer to keep all the code in a single file, perhaps you could create it as an anonymous function (although be careful, as an anonymous function will capture the workspace that it's created in, which depending on where you create it may include a reference to the main object, in which case you'd have a circular reference again.
Edit: Rody's right - my apologies, I read the problem too fast and didn't notice that getData actually sets the Value property rather than just returning the data. Rody's solution in his answer may be an alternative workaround, but like he says - yuck. I'd just call delete manually.

Intriguing problem! :)
I found a workaround, but it's not going to be pretty.
You cannot use an anonymous function. That would capture the local workspace, which will contain a reference to obj. You'll have to use one level of indirection (to a Static method, otherwise, you'd have the same problem).
This static method can safely return a function handle. This function handle is to a function, which has to be passed the instrument object.
Setting the Value property is of course impossible without passing a reference to the object, so, you'll have to create a global state in the function, a variadic call signature, and a getter for the Value property.
I have the feeling I've over-engineered this a bit (it's Friday after all), so if anyone sees a simpler way, please correct me. Anyway, here's what I mean:
classdef sensor < handle
properties
s
end
properties (Dependent)
Value
end
methods
function obj = sensor(port)
obj.s = serial(port);
% You cannot use function handle without implicitly passing obj into
% it. Instead, get a function handle from another function, one that
% does not have this problem:
obj.s.BytesAvailableFcn = sensor.getGetData(obj.s);
fopen(obj.s);
end
function delete(obj)
disp('called destructor');
try %#ok<TRYNC>
fclose(obj.s);
delete(obj.s);
end
end
% Use a getter for Value, so that whenever you query the Value property,
% you get the most recently read sensor data
function V = get.Value(obj) %#ok<MANU>
V = getData();
end
end
% Use indirection to a Static method, to avoid referencing obj implicitly
methods (Access = private, Static)
function f = getGetData(S)
f = #(o,e)getData(S);
end
end
end
% The actual sensor reader
function data = getData(S)
persistent port
if nargin == 1
port = S; return; end
try
data = fscanf(port, '%d');
catch ME
% ...
end
end
Just....yuck.

Related

Matlab alter attribute value by method

I tried to change an attribute value of a class by invoking one of its member function:
p1 = tank();
p1.checkOri(p1);
And in the class definition, I have that static method:
classdef tank
properties
value
...
end
methods
...
methods (Static)
function obj = checkOri(obj)
if (CONDITION) %the thing I want it to do
obj.value = EXPRESSION;
...
Yet this checkOri method is not working. But if I write this method in the main file, or to say altering the value of p1-the instance of class tank-it works perfectly:
p1 = tank();
p1.checkOri(p1);
if (CONDITION) %the thing I want it to do
p1.value = EXPRESSION;
It works perfectly.
I wonder what caused this. From my experience with other programming languages, invoking method should have worked, is it because of some tricks with Matlab syntax or static method? How could I fix it so that this method would work?
So, as #Navan in the comment said, handle class could be a solution.
It appears Matlab has a similar parameter concept with Java and C++, arguments modified in a function/method only remains that modification inside the function/method.
For this class, I simply added < handle in the head of class definition and it worked:
classdef tank < handle
properties
...
But I am not sure if that is the only solution, there might be better ways to do this. So I'll leave that question open, you are more than welcomed to post your opinion:D
In MATLAB, the call
p1.checkOri();
is equivalent to
checkOri(p1);
In both cases, the class method checkOri is called for the class of object p1, passing p1 as first argument to the function by value.
Because p1 is passed by value, any changes made to it inside the function are not seen by the object in the calling workspace. Therefore, one typically does
p1 = checkOri(p1);
This way, the object that was passed by value and modified inside the function is passed back out and assigned to the variable that held the original object.
If the method is written as follows:
function obj = checkOri(obj)
%...
end
then MATLAB will optimize the above function call such that no copy of the object is actually made. Note that both in the function declaration and in the function call, the input and output variable is the same.
As already discovered by OP, the above does not hold for handle classes, classes that inherit from handle. These classes act as if they are always passed by reference, and any change made to them in any workspace will be reflected in all other copies in other workspaces.
Also assigning to a member variable does not follow the above, such that
p1.value = 0;
modifies object p1.
For more information on the difference between value classes and handle classes see this other question.

Save custom objects as struct in matlab

Data tends to survive longer than code. So I want to save my objects as struct.
The idea is to overwrite the saveobj method calling struct recursively on itself.
classdef foo < handle
properties
Data = 12
end
methods
function data = saveobj(o)
data = struct(o);
end
end
end
I now call:
>> bar = foo;
>> save('test', 'bar')
>> bar2 = load('test')
>> class(bar2.bar)
'foo'
However the saved object is still of type foo. Any help figuring out where I screwed up would be appreciated. Thanks
In case it matters I'm using R2012a on RHLE6
The "problem" is that despite the documentation implying that the output from saveobj gets saved with no knowledge that it originated from an object, that is not the case. The structure knows that it came from an object, and when loaded will get passed to a loadobj method if it exists, or the constructor if it doesn't.
One way to overcome this is to overload save, and then call save on the struct within the save method of the object; another is to have a method that returns a struct and then call save on that struct. There are probably also some hacks that can be done to make it a little more automatic, which is most likely what you really want.
I found a truly ugly hack-around, which might help somebody. Due to its ugliness I will however still wait for an answer.
As Phil already pointed out is the class name still stored with the file. However we can trick matlab with an other file with the same name.
My original class looks like this:
classdef foo < handle
%// This is the original class used to some stuff and it holds
%// important data. But I lost it over time...
properties
Data = 12
end
methods
function data = saveobj(o)
for f = properties(o)'
data.(f{1}) = saveobj(o.(f{1}));
end
end
end
end
Now, since I assume I don't have the original source anymore I can use a dummy class to load the data.
classdef foo < handle
%// This is the pretender class source. Since I lost the source of
%// the original class.
methods (Static)
function data = loadobj(data)
global DATA
DATA = data;
end
end
end
The load will naturally fail, but I can extract the struct feed into the loadobj method by calling:
global DATA
As I said a very ugly solution. That's why I'll wait till somebody smart comes around and finds a better way to solve this problem, but I thought I post it in case it helps somebody.
Another hack-around might be to save the class-code while saving the object.
For loading the object of your class, you could first load the code, store it as a m-file and then load the object of the class.

Matlab class basics

I'm having some trouble creating classes in matlab and I don't really understand the method behind it (i'm fairly new to it)
here is my attempt at basic addition using matlab
classdef test
properties
a
b
end
methods
function add = plus(a, b)
end
end
end
assigning values via
p=test(), p.a=5
etc seems to work fine, however attempting p.add returns the error
No appropriate method, property, or field add for class test.
Any help or guidance would be appretiated, thanks.
Methods are defined exactly as functions are with respect to names and outputs.
Therefore, the method is called plus, the output the method should calculate is called add, and the way you probably wanted to write the method is:
function out = add(this)
out = this.a + this.b;
end
Now you call the method as
p.add();

Maximum recursion limit - property values set back to NaN

I am having a go at matlab object orientated programming. I have a class with properties. The properties are computed if they are NaN otherwise the property is returned.
So I have this section:
properties
some_property = NaN;
end
and a property is computed like this:
function some_property = get_some_property(obj)
if(isnan(obj.some_property))
% do some expensive computation
obj.some_property = ...;
end
some_property = obj.some_property;
A get_some_property method can be used by another get_some_property method. The problem is that between method calls properties are set back to NaN. This causes the error:
Maximum recursion limit ...
Any ideas? Thanks.
Your problem is that your class is not derived from handle, so it's passed around as a value. This means that when you call get_some_property, Matlab faithfully duplicates obj, giving a copy to the function get_some_property and keeping that separate from the copy of the code that called get_some_property. So, when you change some_property in the function get_some_property, it changes the property on the value of obj in the function, but not the property of obj in the code that called it.
There are two solutions to your problem. The best solution (IMO) is to derive your class from handle. Classes derived from handle are passed as references, so when you change the property on obj, it will change the property everywhere.
However, if you're unwilling to do this, then you can return obj from get_some_property:
function [some_property,obj] = get_some_property(obj)
And then call get_some_property in this way:
[property,obj] = get_some_property(obj);
This updates the value of obj in the calling namespace. It's both awkward and clunky; I would derive your classes from handle unless there's a good reason to avoid it.

Matlab Class Method Error

I'm new to matlab classes and have just gone through a couple tutorials and now am trying to make one. In my methods section however, I'm having trouble with what I've been trying to do. The object should only need a single piece of info to construct the remaining properties which I will pass as input to the constructor. I was then thinking that I should be able to call two more functions in the methods section to fill in the remaining properties... see pseudocode below...
methods
function obj=myConstructor(input)
obj.property1=input;
getProperty2(obj);
getProperty3(obj);
end
function getProperty2(obj)
obj.property2 = do something and save in property2...
end
function getProperty3(obj)
obj.property3 = do something and save in property3...
end
end
However, when I try and run this, neither property 2 or 3 are assigned... only the value that I pass to the constructor. Any help/ideas on how to accomplish the initialization would be much appreciated. Thanks.
First of all, get methods are usually used to retrieve (i.e. get) the value of a property of an object. Not to calculate something.
Next, the MATLAB object model has two different kinds: value objects and handle objects. The distinction is important, but as you don't mention any, I will assume you are using value objects. The behavior for handle objects is totally different.
In contrast to e.g. Java and most other languages, you need to return the changed object. So in MATLAB this would be something like:
classdef MyClass
properties
p1, p2, p3;
end
methods
function obj = MyClass(input)
obj.p1 = input;
obj = obj.calculateP2(input);
obj = obj.calculateP3(input);
end
function obj = calculateP2(obj, input)
obj.p2 = someLengthyCalculation(input);
end
function obj = calculateP3(obj, input)
obj.p3 = someOtherLengthyCalculation(input);
end
end
end
This can be made more clean, as most likely the calculateP? methods belong better as private static methods. This all depends on how much you want to pass to these methods.