i have a class called sampleClass with a cell array member variable called list.
Now i am trying to add elements to the internal list. For this purpose, i created the method addToList. The method simply tries to add elements to the list.
classdef sampleClass
properties
list = {}
end
methods
function addToList(obj)
obj.list{end+1}='test';
obj.list
end
end
end
Now the problem is, that the elements are not stored in the list.
Inside the function addToList the following output signalizes that the element is stored in the list:
>> samp = sampleClass();
>> samp.addToList
ans =
'test'
But after leaving the function, the element is no longer accessible:
>> samp.list
ans =
{}
Has anybody an idea what's going wrong? I am using Matlab 7.11.0 (R2010b).
Thanks for your help.
Julien
That's because you forgot to inherit from the handle class:
classdef sampleClass < handle %// Change here!
properties
list = {}
end
methods
function addToList(obj)
obj.list{end+1}='test';
obj.list
end
end
end
If you want to retain the changes made when modifying an instance of your class, you must inherit from the handle class. This can be done by taking your class definition (first line of your code), and doing < handle. If you don't, then any changes you make will not be saved. To show that this works, this is what I get in MATLAB:
>> samp = sampleClass();
>> samp.addToList
ans =
'test'
>> samp.list
ans =
'test'
To be more verbose, here's what the MATLAB docs say about handle:
The handle class is the superclass for all classes that follow handle semantics. A handle is a reference to an object. If you copy an object's handle, MATLAB® copies only the handle and both the original and copy refer to the same object data. If a function modifies a handle object passed as an input argument, the modification affects the original input object.
As such, you need to inherit from the handle class so that you have a reference back to the object you created. Any changes you make to the instance of your class will be remembered if you inherit from handle. If you don't, no changes you make get registered.
Related
classdef Dog < handle
properties
data;
end
methods
function self = Dog(varargin)
disp("Dog()")
end
function out = new(~)
out = Dog();
out('bark') = 1;
end
end
end
d=Dog(); why does d.new() print below?
Dog()
Dog()
Dog()
It also bypasses subsref if I overload it. Entering d in console gives
ans =
1×114 Dog array with properties:
data
and isn't reproduced with d('bark') = 1.
The behavior changes if I get rid of varargin, instead there's an error. Also why 1x114?
Here is what's happening when calling d.new() (after d = Dog()):
out = Dog(); is invoked. This constructor call triggers the first output of "Dog()"
out('bark') = 1; is invoked, which triggers the following:
The characters of 'bark' are interpreted as values [98 97 114 107 ]. Consequently, Matlab resizes out to a size of 114.
To construct a Dog object to fill positions [98 97 114 107 ] in out, Matlab calls the constructor again, this time with the input argument varargin equal to { 1 }. This triggers the second output of "Dog()".
To construct a Dog object to fill the other positions in out, Matlab calls the constructor again, this time with no input argument. This triggers the third output of "Dog()".
Furthermore, subsref is not bypassed, but simply not called, as you do not refer to the object in a reading manner.
And when you remove varargin, you get the error, because the constructor cannot be called anymore with one input argument, as explained in the second bullet point under 2. above.
As I understand it, within class methods, indexing expressions always use the built-in subsasgn and subsref, not the overloaded (customized) one you might write yourself. This is so that overloading these functions doesn't remove the ability of class methods to access object properties.
So, within your class method, out(i) accesses the ith object in the array out. This is not out.data(i), out is really an array of objects of class Dog. Dog() creates a 1x1 array, which you would normally think of as an object, but it really is an array. Everything in MATLAB is an array!
Now for out('bark') = 1. 'bark', as explained by user16372530's anwser, is a 4-element array, with numeric values [98 97 114 107]. Thus out, which starts off as a 1x1 array of your custom class, is resized to an array of 114 elements, and to 4 of those elements you assign 1. Here, MATLAB needs to create an empty element to fill out the 113 new elements, so calls Dog() once and copies the result to each of those elements. Then it needs to convert 1 to your class, so calls Dog(1) to do so, and copies to result to the 4 indexed elements. Actually, as indicated by
user16372530 in a comment below, first 1 is converted and then the empty object is created.
If you want your class method to use the overloaded indexing operator, you need to explicitly call subsasgn or subsref, which is ugly and hard to read. There really is no way, as far as I understand it, to use class objects inside the class methods as you actually intend your class to be used. The same code behaves differently inside a class method and outside of it.
MATLAB OOP has some really interesting features, but it also has a lot of weird and inconvenient things. I guess they did their best designing a custom class system within the previously existing MATLAB array syntax.
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.
I defined a class in one of my many MATLAB packages. To my suprise, I could not access a constant property of my class without importing the class definition. Even if it is a method of the class itself. Like so:
classdef TestClass
properties( Constant )
c=0;
end
methods
function obj = TestClass()
end
function getC(obj)
import test.TestClass;
disp(TestClass.c);
end
end
end
I just want to check whether I am doing something wrong here or is this the correct way to use constants in MATLAB.
Since you have placed TestClass inside a package Matlab needs to know where to look to find the definition for this class, even if it's a reference from within the class or function. An alternate to the above code could be:
function getC(obj)
disp(test.TestClass.c);
end
Alternately, if within a class, constant values can be accessed from the object itself.
function getC(obj)
disp(obj.c);
end
If neither of these is working for you, you may need to refresh the classdef for TestClass from memory. This will cause matlab to reload the constant value, which is pulled into Matlab when it first parses the classdef file to determine the structure of the class. This can be done using clear classes, however a warning that it will also clear all other classes, variables, and any breakpoints you have set.
If you want to see if this is necessary you can view the metaclass object to determine what Matlab "thinks" your class structure should be. You can do this using the following.
mc = ?test.TestClass;
mc.PropertyList
You may need to index into the property list to find the specific property you are interested in, but the thing you are looking for are the following fields.
Name: 'c'
Constant: 1
DefaultValue: 0
I am having some issues with matlab now that I have added a new variable to a class.
I have tried using clear classes as the error message says to but this seems to still produce the same message. I have also tried every clear command possible, rehash commands, restarting matlab and am now completely out of ideas..
Don't suppose anyone else has any? I'm using matlab 2013b if that's any use!
Cheers!
Since you're not providing much info, let me show what I get with a simple example running on R2014a. Consider the following class:
MyClass.m
classdef MyClass
properties
x
end
end
First I create an object of this class:
>> a = MyClass()
a =
MyClass with properties:
x: []
Next I modify the above by adding a new property y, and saving the MyClass.m file:
MyClass.m (after change)
classdef MyClass
properties
x
y %# <-- added
end
end
Now if I try to create another instance of the class, I get the following warning:
>> b = MyClass()
Warning: The class file for 'MyClass' has been changed, but the change cannot be applied because objects
based on the old class file still exist. If you use those objects, you might get unexpected results. You
can use the 'clear' command to remove those objects. See 'help clear' for information on how to remove
those objects.
b =
MyClass with properties:
x: []
As indicated, we won't see the changes until we clear all instances of the old class:
>> whos
Name Size Bytes Class Attributes
a 1x1 104 MyClass
b 1x1 104 MyClass
>> clear classes
>> whos
>> b = MyClass()
b =
MyClass with properties:
x: []
y: []
Now the modifications are picked up by the new object.
Note that in some cases, MATLAB might still hold references to objects not visible in the base workspace (like if you have globals, locked functions, or GUIs with data saved in the app/user data section of the GUI). Usually closing all figures and clearing all variables will remedy the situation. If not, restarting MATLAB will most definitely get could back to a clean slate.
UPDATE:
This is a known bug - link requires a login to Mathworks to access it.
Summary of bug report
An instance of a MATLAB user-defined
class saved to a MAT file using
Version 7.6 (R2008a) might not load
properly if one of its property values
is an instance of a different MATLAB
class.
Briefly, Mathworks reports that a previously saved top level custom object may be loaded incorrectly (as described below) and that the error occurs on the SAVE step. So, the data is corrupted inside the MAT file.
From my experience this seems to be intermittent. In one data analysis application I wrote out of 75 MAT files 37 were saved with this corruption :(
Be careful with user defined objects. I added the following test on save to make sure that the data is not corrupted
save('MAT_file_name.mat');
tmp=load('MAT_file_name.mat');
if ~isa(tmp.bb,'superClass')
msgbox({'THE FILE WAS NOT SAVED PROPERLY', ...
' ', ...
[' MAT_file_name.mat',]})
end
Orginal Question
Here I am using MATLAB 2008a. This subtle bug is fixed in MATLAB-2009a.
Anyway, the way my two classes are defined, the save/load cycle causes the variables of one class (superClass) to be loaded as variables of my second class (propClass).
Example MATLAB (r2008a) Session
>> bb=superClass;
>> whos
Name Size Bytes Class Attributes
bb 1x1 60 superClass
>> save
>> clear
>> clear classes
>> load
>> whos
Name Size Bytes Class Attributes
bb 1x1 60 propClass
After loading matlab.mat, the variable bb has mysteriously changed from superClass to propClass
Class: superClass
This class needs to contain an array of type propClass and here is it's Naive definition
classdef superClass<handle
properties(SetAccess=private)
a = propClass.empty % need to set this property as type propClass
% otherwise the addProp method throws an error
count=0;
end
methods
function self=superClass
%empty class definitionS
end
function addProp(self)
p = propClass;
self.count = self.count+1;
self.a(self.count)=p;
end
end
end
Class: propClass
PropClass is a second class used by the super class. Its definition is not important for this bug.
Question
So, why is superClass being changed to propClass after the load operation in MATLAB-R2008a? Secondly, how can I change the definition of superClass to avoid this symptom?
Note
I ran into this symptom in a larger class I had written and narrowed down the source of the problem. I know it occurs in the MATLAB session described above but it seems that if I add an object to the property array in superClass then the problem disappears.
So, if I call superClass.addProp before saving then the strange change from superClass to propClass doesn't occur.
That's a strange problem! I haven't come across anything like that, but one thing you could try first is to move the initializations of the properties to the constructor:
classdef superClass < handle
properties (SetAccess = private)
a
count
end
methods
function self = superClass
self.a = propClass.empty;
self.count = 0;
end
function addProp(self)
p = propClass;
self.count = self.count+1;
self.a(self.count) = p;
end
end
end
I'm not sure it will have any effect, but that's the only thing I can think of to try. Hope it helps! =)