I want to call a method from a class. For example, I have:
classdef SweepLine
properties
y;
count;
sections;
end
methods
function obj = SweepLine(y)
obj.y = y;
obj.count = 0;
end
function AddSection(obj, section)
obj.count = obj.count + 1;
fprintf('%d\n', obj.count);
fprintf('Indext is: %d\n', section.index);
obj.sections(obj.count) = section;
end
end
end
When I call the method AddSection in a different script, like so:
AddSection(sweepLine, Sections(i)); % Sections contains 10 section objects
I got this error:
The following error occurred converting from Section to double:
Error using double
Conversion to double from Section is not possible.
Error in SweepLine/AddSection (line 20)
obj.sections(obj.count) = section;
I guess this is because I did not do the memory preallocation, but I'm still not sure.
I just moved to MATLAB OOP from Java, and feel that there are a tons of things that are hard to get well with.
Any help about this question and MATLAB programming is really appreciated!
It looks like you are trying to concatenate the sections array with a new value. When you do this, you are assuming that obj.sections has already been allocated, and by doing that assignment you are getting that error. As such, what you have suspected is correct. To get around this, try doing this statement instead in your AddSections method for your class:
obj.sections = [obj.sections section];
This will concatenate section with the currently established obj.sections. This essentially adds section to the end of the array, which is what your previous code is doing. This is safe for empty arrays as well as allocated ones.
I would also recommend that your SweepLine class inherit from the handle class. I'm assuming that when you call AddSection, you don't want the object to be returned. You just want to modify the object, and return nothing...right? If this is the case, then you must inherit from the handle class. However, if you are returning the current instance of the object after each method call, then this isn't required.
In any case, you should do this:
classdef SweepLine < handle
properties
y;
count;
sections;
end
methods
function obj = SweepLine(y)
obj.y = y;
obj.count = 0;
end
function AddSection(obj, section)
obj.count = obj.count + 1;
fprintf('%d\n', obj.count);
fprintf('Index is: %d\n', section.index);
obj.sections = [obj.sections section];
end
end
end
Related
I'm having a weird problem using object oriented matlab, and I'm not sure if I'm completely missing something, or I've hit some unusual behaviour.
I have a superclass defined as follows:
classdef (Abstract) AbstractSimulationData < matlab.mixin.Heterogeneous
properties (Abstract)
name
data
end
properties
timeStamp = -1
end
methods (Abstract)
CalculateData(obj, t)
end
methods
function data = GetData(obj, t)
if obj.timeStamp == t.t
data = obj.data;
else
obj.timeStamp = t.t;
obj.CalculateData(t);
data = obj.data;
end
end
end
end
When the concrete class implements the method CalculateData I intend it to set the superclass property data.
Two concrete classes from this are:
classdef A < AbstractSimulationData
properties
name = 'A'
data = []
end
methods
function obj = A
% No special initialisation
end
function CalculateData(obj, t)
test = t.B.GetData(t)
obj.data = rand(2,10);
end
end
end
And:
classdef B < AbstractSimulationData
properties
name = 'B'
data = containers.Map
end
methods
function obj = B
% No special initialisation
end
function CalculateData(obj, t)
if isempty(obj.data)
obj.data('left') = 1;
obj.data('right') = 2;
end
% Other operations
end
end
end
Within the A.CalculateData method I call the GetData method for B. This in turn calls the B.CalculateData method.
Now, as it filters back up, the data property gets set correctly so that B.GetData returns the value that was set in B.CalculateData.
But, when I go the next step up to A.GetData it returns [], the initialised value. Going through debug mode, the calculations definitely work in A.CalculateData and it seems to set data correctly, but when it jumps back up to the superclass obj.data is the default value from A.
A minimum working example to get this behaviour:
t.B = B();
t.t = 1;
a = A;
a.GetData(t);
>> test =
Map with properties:
Count: 2
KeyType: char
ValueType: any
>> ans =
[]
This is all part of a pretty big project, so it's hard to give the full context, but if it's possible from this, can someone explain why setting superclass data works for B but not A?
If it makes a difference B is returning a container.Map and A is returning 2xn matrix.
As far as I can tell from the documentation, it should work.
Short-short version
Is it possible to get an handle to a subclass of Copyable rather than getting a copy?
Context
I have a class hierarchy that i want to have Copyable.
classdef A < matlab.mixins.Copyable
properties
stuff;
end
methods
function action(self)
% ...
end
end
end
Various subclasses provide variations on the main behavior, and a particular subclass works to aggregate several of those behviors for sequenctial application
classdef multiA < classA
properties
nElements = 1;
elements;
iElement = 0;
currentElement;
end
methods
function self = multiA()
end
function addElement(self, fhdl)
if self.nElements == 0
self.nElements = 1;
self.elements = {fhdl}; % Store handles to constructors
else
self.nElements = self.nElements + 1;
self.elements(self.nElements) = fhdl; % Store handles to constructors
end
end
function nextElement(self)
if self.iElement < self.nElements
self.iElement = self.iElement + 1;
fhdl = self.elements(self.iElement);
self.element = fhdl(); % instantiate with constructors
end
end
function action(self)
if self.iElement > 0 && self.iElement <= self.nElements
self.currentElement.action(); % Pass use request to constructed objects
end
end
end
end
The user is expected to build up objects with addElement, and work through the list with nextElement invoking the behavior of the contained objects as needed with `action.
multi = multiA();
multi.addElement( #OneSubClass );
multi.addElement( #AnotherSubClass );
multi.addElement( #ThirdSubClass );
% ...
multi.nextElement();
multi.action();
The problem emerges
The multiA class passes some basic unit tests and I started trying to apply it. And it seemed to be working. Then I get a situation where multi.action() seems to be flipping unpredictably back and forth between two behaviors.
It seems unlikely, but just conceivable that somehow the object of type OneSubClass is sticking around after I have moved on to AnotherSubClass.
The (wrong?) solution
Write a unit test which captures the handle of each element as it is instantiate and checks that this remains the handle in use until the next one is instantiated. Something like:
multiA.nextElement();
ehdl = multiA.currentElement;
% do things
testCase.veriftySameHandle(multiA.currentElement,ehdl);
Alas ehdl seems to be a copy of the stored element rather than a handle to it even though I have not explicitly invoked copy(). (I say that because ehdl retains the state of the contained object at the time of nextElement() while the fresh access of currentElement shows the expected changes.)
Is there a way to force the retention of a handle to an object derived from matlab.mixins.Copyable?
i have this superClass
classdef SysSignal<handle
%SIGNALP Summary of this class goes here
% Detailed explanation goes here
properties (SetAccess = public, GetAccess = public )
SetOfSignal = containers.Map('KeyType','char', 'ValueType', 'any')
end
methods
%constructor
function sys=SysSignal()
end
function sys=adds(sys,varargin)
%convert form cell to signalup
for n=1:length(varargin)
signal=varargin{1,n};
if isempty(signal.name)
continue
else
%add to the map
sys.SetOfSignal(signal.name)= signal;
end
end
end
and that child class
classdef Signalp<SysSignal
%SIGNALP Summary of this class goes here
% Detailed explanation goes here
properties
name
lineNo
color='red'
sumrole
end
properties (SetAccess=private,GetAccess=public)
arrPrice
LineLength
LineProportion
end
methods
%constructor
function sig=Signalp(varargin)
end
end
end
now i want to change the properties like this:
sys=SysSignal;
s=Signalp;
s.name='dd';
sys.adds(s)
sys.SetOfSignal('dd').sumrole='hello'
but i get that error :
??? Error using ==> subsasgn
Only one level of indexing is supported by a containers.Map.
how can i change the values from the superClass?
The answer is to seperate sys.SetOfSignal('dd').sumrole='hello' into two statements:
dd = sys.SetOfSignal('dd');
dd.sumrole='hello'
That is because sys.SetOfSignal('dd').sumrole doesn't do what you'd intuitively think it does. Indeed the containers.Map class overloads the subscripted reference and subscripted assignment operators. In essence they 'intercepts' the (), {} and . operators at the same time (ie .sumrole is 'sent' to the map.Containers object - instead of your object!). In my opinion that's a really weird design decision but we must live with it!
Have a look at these links for more info:
subsref, subsasgn
gregswiss's answer is correct, except that accessing the containers map creates a copy, so you finish by replacing the old value with the new modified one
dd = sys.SetOfSignal('dd');
dd.sumrole='hello'
sys.SetOfSignal('dd') = dd;
Dear lovely community,
I already looked in Google and in the forum and also found some interesting posts. But in the end I still didn't get it worked. So, I am going to post the question here. I know in Matlab are already get/ Set methods implemented, but I am using objects and therefore I didn't understand where to implement them.
Overall Structure:
+Measurement\MeasurerIF
+Measurement\MeasurerComponent
In my Interface I declare my functions I want to implement and this Interface is furthermore abstract. It looks like this:
classdef MeasuererIF < handle
methods (Abstract=true)
getStatus(cObj) ;
setStatus(cObj,iStatus) ;
getInfo(cObj) ;
setInfo(cObj,sInfo) ;
end
end
Then I created the other class MeasurerComponent in which I implemented the methods and also the constructor:
classdef MeasurerComponent < PerformanceMeasurement.MeasuererIF
%% MeasurerComponent: Evaluates which model is used and contains them as childs.
% Detailed explanation goes here
properties (Access=protected)
miStatus;
msInfo;
mcData;
end
methods
%constructor
function cObj = PerformanceMeasurement.MeasurerComponent ;
cObj.miStatus = -1 ;
cObj.msInfo = 'Import' ;
cObj.mcData = [] ;
end
%Status
function setStatus(cObj,iStatus)
cObj.miStatus = iStatus;
end
function iStatus = getStatus(cObj)
iStatus = cObj.miStatus;
end
%Info
function setInfo(cObj,sInfo)
cObj.msInfo = sInfo;
end
function sInfo = getInfo(cObj)
sInfo = cObj.msInfo ;
end
end
end
Earlier I just used the getMethods and recently added the setMethods and now it doesn't work anymore. The Problem is that when I create an object
obj = Measurement.MeasurerComponent
the programm doesn't initialize the values anymore.
For a = obj.getInfo;
I receive just []
Does someone has an idea why it doesn't get initialized anymore? After I received a tip I changed the initialization process to the constructor due to the handle class.
I am really thankful and glad about each hint and tip!
Cheers
Your constructor should be defined by function cObj = MeasurerComponent, without the PerformanceMeasurement prefix. This is just the way that packages are defined and used in Matlab - you add the prefix if using the class from outside the package, but not within the package (explained here: "Note that definitions do not use the package prefix" -
http://uk.mathworks.com/help/matlab/matlab_oop/scoping-classes-with-packages.html?refresh=true).
Also, you have a typo - your abstract parent class file is called +Measurement\MeasurerIF but in the definition you spell it MeasuererIF. It doesn't matter which one it is called, but the name of the class does have to match the filename!
If I correct both of these issues, then your code becomes
+Measurement\MeasurerIF
classdef MeasurerIF < handle
methods (Abstract=true)
getStatus(cObj)
setStatus(cObj,iStatus)
getInfo(cObj)
setInfo(cObj,sInfo)
end
end
+Measurement\MeasurerIF
classdef MeasurerComponent < Measurement.MeasurerIF
%% MeasurerComponent: Evaluates which model is used and contains them
%% as childs.
properties (Access=protected)
miStatus
msInfo
mcData
end
methods
%constructor
function cObj = MeasurerComponent
cObj.miStatus = -1 ;
cObj.msInfo = 'Import' ;
cObj.mcData = [] ;
end
%Status
function setStatus(cObj,iStatus)
cObj.miStatus = iStatus;
end
function iStatus = getStatus(cObj)
iStatus = cObj.miStatus;
end
%Info
function setInfo(cObj,sInfo)
cObj.msInfo = sInfo;
end
function sInfo = getInfo(cObj)
sInfo = cObj.msInfo ;
end
end
end
and if I type the following:
obj = Measurement.MeasurerComponent;
obj.getInfo
then I get back
ans =
Import
which is what I expect.
I am running into an infuriating problem with Matlab, and an earlier answer to apparently the same problem didn't help me, unfortunately. I apologize that the question is rather long - you need quite a bit of information to reproduce the problem (I tried to trim it as much as I could...)
The problem is this: No matter what I do, after I have used a class I cannot "make Matlab forget". Values used seem to be persistent, and edits to the class definition won't "stick". In the latter case, the error message is:
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.
I get that message even after
>> clear all
>> clear functions
>> clear ans
Somehow the class definition is persistent despite my attempts to clear it. To make matters worse, when I modify a value of an instance of the class, then clear it, the value is somehow not "forgotten". To illustrate, here is the source code of myClass:
% a simple class definition that shows the problem that I cannot
% figure out how to redefine a class without restarting Matlab
classdef myClass < handle
properties
precursors = {'none'};
numPre = {1};
value = 1;
end
methods
function obj = myClass(pre, num, val)
% constructor
if nargin > 0
obj.precursors = pre;
obj.numPre = num;
obj.value = val;
end
end
function v = sumVal(obj)
% find the sum of the value of all precursors
n = numel(obj.precursors);
v = 0;
for ii = 1:n
pc = obj.precursors{ii};
if isa(pc, 'myClass')
if ii==1
v = 0;
end
v = v + sumVal(pc) * obj.numPre{ii};
else
v = obj.value;
end
end
end
end
% only the following named instances may exist:
enumeration
grandpa ({'none'}, {1}, 1)
father ({myClass.grandpa}, {3}, -1)
son ({myClass.father}, {2}, -1)
end
end
In a fresh instance of Matlab, I do the following:
>> son = myClass.son;
>> sumVal(son)
ans =
6
>> grandpa = myClass.grandpa;
>> grandpa.value = 5;
>> sumVal(son)
ans =
30
So far, so good. The sumVal function discovers the fathers and grandfathers, and the sumVal is computed correctly (6 * 1 in the first case, 6 * 5 in the second case).
Now I delete "everything" (I think):
>> clear all
>> clear functions
>> clear ans
And I create just one variable:
>> son = myClass.son;
Now comes the kicker - the unexpected answer
>> sumVal(son)
ans =
30
When I inspect the variables loaded, I find
>> whos
Name Size Bytes Class Attributes
son 1x1 112 myClass
There is no grandpa instance, and the class definition file was not touched. Yet, the value of grandpa (which I created, then deleted) is somehow persistent.
And when I make a small change to the myClass.m file, and try to create a new variable (after a clear all), I get the message shown above. All of which leads me to my question:
Where is Matlab hiding an instance of my class so that variables are persistent after a clear all, and how do I clear the workspace (without restarting) so the class definition is "reset"?
I don't know if it matters, but I'm using Matlab 7.14.0.739 (R2012a)
You have an intermediate instance myClass.father that is not being destroyed by MATLAB. You have to deleteit yourself
>> clear grandpa
>> delete(son.precursors{1})
>> clear son
>> clear classes
>> son = myClass.son
son =
son
>> sumVal(son)
ans =
6
Edit:
Alternatively, you can add a destructor to your class
function delete(obj)
if isa(obj.precursors{1}, 'myClass')
delete(obj.precursors{1});
end
end
and use delete(son) instead of leaving it to clear function to destroy. You can extend this to your case and recursively delete all instances in your tree.
Those instances are "hiding" in the myClass enumeration class itself. Matlab is storing a reference to each of those named instances so when you reference them like myClass.father you get the same object back, instead of it constructing a new one. Probably similar to how values are stored in Constant properties on classes.
If you have any other classes that refer to the myClass.xxx enumerated instances in Constant properties, enumerations, or persistent variables, they could also be holding on to references to them.
Try doing clear classes a few times in a row instead of just once.
To help debug this, you could put a couple debugging printf() statements in the constructor and destructor for this class, so you can see when the instances are really created and cleaned up.
function obj = myClass(pre, num, val)
% constructor
if nargin > 0
obj.precursors = pre;
obj.numPre = num;
obj.value = val;
end
printf('myClass: created (%d, %d, nargin=%d)\n', obj.numPre, obj.value, nargin);
end
function delete(obj)
printf('myClass: deleting (%d, %d)\n', obj.numPre, obj.value);
end