Sorry about the formatting, i pasted and then applied the {} control but it still looks mangled. Please educate me if i'm misusing the tool somehow.
I have a base class:
classdef SystemNode < matlab.mixin.Heterogeneous
properties (Abstract)
description
quantity
parent
unit_cost
learning_curve
average_cost
total_cost
children
end
end
I have a descendant:
classdef Subsystem < models.system.SystemNode
properties
description
quantity
parent
children
key
end
properties (Dependent)
unit_cost
learning_curve
average_cost
total_cost
end
methods
function self = Subsystem(description, quantity, parent)
% TODO: Validate Inputs
self.description = description;
self.quantity = quantity;
self.parent = parent;
self.children = [];
self.key = char(java.util.UUID.randomUUID().toString());
end
function add_child(self, node)
% TODO: Validate Inputs
self.children = [self.children node];
end
function unit_cost = get.unit_cost(self)
% Cost if there were only one.
unit_cost = 0;
for child = self.children
unit_cost = child.unit_cost;
end
unit_cost = unit_cost*self.quantity;
end
function learning_curve = get.learning_curve(self)
learning_curve = 0;
end
I can't get .add_child() to work.
for example:
>> ss = models.system.Subsystem('test', 1, []);
>> ss.add_child('a')
>> ss.children
ans =
[]
If i descendend my abstract class from handle instead of the Mixin this works fine. What am i doing wrong??
BTW. I am using Matlab 2011b
Thanks in advance.
It's handle that makes the object behave in a pass-by-reference manner. If you want this kind of behavior, try the following:
classdef SystemNode < matlab.mixin.Heterogeneous & handle
If you do not inherit from handle, you get normal Matlab pass-by-value behavior. In this case, if you want to update the state of an object, you have to return the updated object from the setter method, and store the returned updated value.
So the setter has to return the updated self.
function self = add_child(self, node)
self.children = [self.children node];
end
And calls to it store the returned updated object.
ss = ss.add_child('a')
If you don't store a new value in ss, you're still looking at the value of ss from before the add_child call, with no children.
Related
How to inherit a new class player from class actor and make method actor:new(x, y, s) called in method player:new(x, y, s) with the same parameters. I need to make player:new the same but with additional parameters so the player can have more properties than actor.
Is there a way to do this not only in new method, but in other methods, like player:move(x, y) will call actor:move(x, y) or self:move(x, y) but with additional code?
I use this pattern to make classes in modules:
local actor = {}
function actor:new(x, y, s)
self.__index = self
return setmetatable({
posx = x,
posy = y,
sprite = s
}, self)
end
-- methods
return actor
A good way to do this is to have a separate function that initializes your instance. Then you can simply call the base classes initialization within the inherited class.
Like in this example: http://lua-users.org/wiki/ObjectOrientationTutorial
function CreateClass(...)
-- "cls" is the new class
local cls, bases = {}, {...}
-- copy base class contents into the new class
for i, base in ipairs(bases) do
for k, v in pairs(base) do
cls[k] = v
end
end
-- set the class's __index, and start filling an "is_a" table that contains this class and all of its bases
-- so you can do an "instance of" check using my_instance.is_a[MyClass]
cls.__index, cls.is_a = cls, {[cls] = true}
for i, base in ipairs(bases) do
for c in pairs(base.is_a) do
cls.is_a[c] = true
end
cls.is_a[base] = true
end
-- the class's __call metamethod
setmetatable(cls, {__call = function (c, ...)
local instance = setmetatable({}, c)
-- run the init method if it's there
local init = instance._init
if init then init(instance, ...) end
return instance
end})
-- return the new class table, that's ready to fill with methods
return cls
end
You would simply do:
actor = CreateClass()
function actor:_init(x,y,s)
self.posx = x
self.posy = y
self.sprite = s
end
player = CreateClass(actor)
function player:_init(x,y,s,name)
actor.init(self, x,y,s)
self.name = name or "John Doe"
end
I am trying to create a class 'Deck' that has methods shuffle and deal, however, I do not know why my function for 'shuffle' isn't running. I get the error message :
Undefined function or method 'shuffle' for input arguments of type 'cell'.
Can someone please explain why the function is not running? thank you very much.
I am calling upon a previously created classdef 'Card'
classdef Deck < handle;
properties;
diamond;
spade
heart;
club;
end;
methods;
function obj=create(deck);
for k=1:13;
%Designate a number to each suit to create the deck
obj(k).diamond=cards('D','R',k);
obj(k).spade=cards('S','B',k);
obj(k).heart=cards('H','R',k);
obj(k).club=cards('C','B',k);
end
%Create a vector of each suit and number accordingly until we
%have 52 cards. 13 of each suit.
obj={obj.diamond obj.spade obj.heart obj.club};
end
%%
function obj=shuffle(obj);
shuff=randperm(52);
for k=1:52;
hf=shuff(k);
obj(k)=obj(hf);
end
end
end
end
You do not need the last line in the constructor:
obj = { obj.diamond obj.spade obj.heart obj.club }
This line turns your object into a cell (?). Try remove this line.
Try this classdef instead
classdef Deck
properties
cards
end
methods
function obj = Deck()
% do your stuff here, but no obj. before diamond/spade/heart/club
obj.cards = { diamond, spade, heart, club };
end
function obj =shuffle ( obj )
obj.cards = obj.cards( randperm(52) );
end
end
I think you want to have a property which is an array of Card objects. See the MATLAB documentation for object arrays. Here's how I would solve this problem:
classdef Deck < handle
properties
% This will be an object array of Card objects.
CardArray
end
properties (Dependent)
nCards
end
methods
function This = Deck()
% preallocate arrays.
% the constructor for Card should accept 0 arguments.
Diamond(13) = Card('D', 'R', 13);
Spade(13) = Card('S', 'B', 13);
Heart(13) = Card('H', 'R', 13);
Club(13) = Card('C', 'B', 13);
% now fill in the rest of each suit
for iVal = 1:12
Diamond(iVal) = Card('D', 'R', iVal);
Spade(iVal) = Card('S', 'B', iVal);
Heart(iVal) = Card('H', 'R', iVal);
Club(iVal) = Card('C', 'B', iVal);
end
% finally concatenate them into a single array
This.CardArray = [Diamond, Spade, Heart, Club];
end
function shuffle(This)
This.CardArray = This.CardArray(randperm(This.nCards));
end
function n = get.nCards(This)
n = length(This.CardArray);
end
end
end
You need to make sure that your Card constructor accepts zero arguments. For example, you could do the following:
classdef Card < handle
properties
symbol = 'D'
color = 'R'
value = 1;
end
methods
function This = Card(varargin)
if nargin >= 1
This.symbol = varargin{1};
end
if nargin >= 2
This.color = varargin{2};
end
if nargin >= 3
This.value = varargin{3};
end
end
end
end
In Matlab, I would like to perform some operations on private members of a class. I would also like to perform this exact same task on other classes as well. The obvious solution is to write a function in a separate M file that all the classes call in order to perform this task. However, that seems impossible in Matlab (see below). Is there another way to accomplish this?
Here is the problem specifically: suppose I have one m file with the contents
classdef PrivateTest
properties (Access=private)
a
end
methods
function this = directWrite(this, v)
this.a = v;
end
function this = sameFileWrite(this, v)
this = writePrivate(this, v);
end
function this = otherFileWrite(this, v)
this = otherFileWritePrivate(this, v);
end
function print(this)
disp(this.a);
end
end
end
function this = writePrivate(this, v)
this.a = v;
end
...and another m file with the contents
function this = otherFileWritePrivate(this, v)
this.a = v;
end
After instantiating p = PrivateTest, both of these commands work fine (as expected):
p = p.directWrite(1);
p = p.sameFileWrite(2);
...but this command doesn't work even though it's the same code, just in a different m file:
p = p.otherFileWrite(3);
So, it seems like any code that performs operations on private properties of a class MUST be in the same m file as the classdef that defines those private properties. Another possibility might be to have all the classes inherit a class with the writing method, but Matlab doesn't allow this either. In one m file, I would have this code:
classdef WriteableA
methods
function this = inheritWrite(this, v)
this.a = v;
end
end
end
...and in another m file I would have this code:
classdef PrivateTestInherit < WriteableA
properties (Access=private)
a
end
end
However, after instantiating p = PrivateTestInherit;, the command p.inheritWrite(4) causes the same error message as before: "Setting the 'a' property of the 'PrivateTestInherit' class is not allowed."
In light of this, How is it possible to generalize code that manipulates private properties in Matlab, or is it possible?
It is not possible to manipulate private properties outside of the class, that is why they are called private. This idea is called encapsulation.
You can in solve it in many ways:
Define public property that wraps the private, and change it. (See code below)
(Inheritance pattern) Do a common father class, your other classes inherit the function
classdef PrivateTest
properties (Access=private)
a
end
properties(Access=public,Dependent)
A
end
methods
function this = set.A(this,val)
this.a = val;
end
function val = get.A(this)
val = this.a;
end
function this = directWrite(this, v)
this.a = v;
end
function this = sameFileWrite(this, v)
this = writePrivate(this, v);
end
function this = otherFileWrite(this, v)
this = otherFileWritePrivate(this, v);
end
function print(this)
disp(this.a);
end
end
end
function this = writePrivate(this, v)
this.A = v;
end
I want to create a subclass, ess say, to the built-in ss class. I'd like to be able to convert an existing ss object to an ess object and at the same time add the missing properties, e.g. w, by something like this
sys=ss(a,b,c,d);
esys=ess(sys,w);
but I can't figure out how to setup the constructor correctly. What is the best way to achieve this? My code currently looks like this
classdef ess < ss
properties
w
end
methods
function obj = ess(varargin)
if nargin>0 && isa(varargin{1},'StateSpaceModel')
super_args{1} = sys;
else
super_args = varargin;
end
obj = obj#ss(super_args{:});
end
end
end
But this does not work as I get the following error:
>> ess(ss(a,b,c,d))
??? When constructing an instance of class 'ess', the constructor must preserve
the class of the returned object.
Of course I could copy all the object properties by hand but it seems to me that there should be some better way.
Here is an example of what I had in mind:
classdef ss < handle
properties
a
b
end
methods
function obj = ss(varargin)
args = {0 0}; %# default values
if nargin > 0, args = varargin; end
obj.a = args{1};
obj.b = args{2};
end
end
end
and:
classdef ess < ss
properties
c
end
methods
function obj = ess(c, varargin)
args = {};
if nargin>1 && isa(varargin{1}, 'ss')
args = getProps(varargin{1});
end
obj#ss(args{:}); %# call base-class constructor
obj.c = c;
end
end
end
%# private function that extracts object properties
function props = getProps(ssObj)
props{1} = ssObj.a;
props{2} = ssObj.b;
end
Lets test those classes:
x = ss(1,2);
xx = ess(3,x)
I get:
xx =
ess handle
Properties:
c: 3
a: 1
b: 2
Methods, Events, Superclasses
Hi I am trying to implement a linked list in Matlab.
The implementation I am hoping to do is (this is the C equivalent):
class Node{
public Node* child;
}
I have looked around but don't seem to get anything quite close.
I guess that you want to implement a linked list:
classdef Node < handle
properties
Next = Node.empty(0); %Better than [] because it has same type as Node.
Data;
end
methods
function this = Node(data)
if ~exist('data','var')
data = [];
end
this.Data = data;
end
end
end
Creation :
n1 = Node('Foo'); %Create one node
n2 = Node('Bar'); %Create another one
n1.Next = n2; %Link between them
Iteration:
n = n1;
while ~isempty(n)
disp(n.Data); %Change this line as you wish
n = n.Next;
end