Maximum recursion limit - property values set back to NaN - matlab

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.

Related

Organizing similar class and instance methods within a class

I have a class, for which I have static methods that calculate something (example below in MATLAB, since that's what I'm using, although I think my question may be more general):
methods (Static)
function out = f(x)
out = x*2;
end
end
Suppose I have instance methods where I want to do the same calculation (and hence use the aforementioned class method), but I also want to do something specific to the class, like updating a property or maybe passing in an instance property into the calculation. So like:
methods
function out = f(this)
out = ClassName.f(this.x); % Use the class method, but pass in an instance variable
end
% OR
function [this, out] = f(this,x)
out = ClassName.f(x)*2; % Use the class method with a provided input
this.value = out; % then assign value to an instance variable
end
end
At least in MATLAB, I can't overload a class method with an instance method (I can overload a built-in MATLAB method within my class, but that's not what I want here), so I'm not sure how to go about this in a proper OOP way. I want to keep the class method there in case someone wants to use the specific calculation on some data they collected outside the class, but I also want the instance method in case someone decides to use the class to collect data and then analyze the data with the built methods.

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.

What is the difference between calling a dependent property of a class with and without parentheses?

Say I have a class like such:
classdef exampleClass
properties (Dependent=true)
x
end
methods
function this=exampleClass(this)
this.x = 4;
end
function x=get.x(this)
x=4;
end
end
end
What's the difference in accessing x as classInstance.x and classInstance.x()?
The function get.x(this) is called a getter of the property x. It actually has nothing to do whether the property has the attribute Dependent or not, it is the same for any type of property.
If you have a setter/getter defined for your property, Matlab will always call the function get.PropertyName or set.PropertyName when you do something like:
tmp_var = my_instance.x
or
my_instance.x = 3.1416;
So if you have in your code my_instance.x or my_instance.x() is practically the same. But if you want to follow best practices, you must avoid the function call.
Now, as an extra point: for performance reasons, it is recommended that you do not use setters/getters because every time you modify your property (even inside your class) you will pay the price of the overhead of the setter/getter.

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

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.

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.