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
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
Is it possible to define a MATLAB class such that the objects from this class can be called like any other function?
IOW, I'm asking whether one can write in MATLAB the equivalent of something like the following Python class:
# define the class FxnClass
class FxnClass(object):
def __init__(self, template):
self.template = template
def __call__(self, x, y, z):
print self.template % locals()
# create an instance of FxnClass
f = FxnClass('x is %(x)r; y is %(y)r; z is %(z)r')
# call the instance of FxnClass
f(3, 'two', False)
...
[OUTPUT]
x is 3; y is 'two'; z is False
Thanks!
I do not know, whether MATLAB directly supports what you want, but MATLAB does support first-class functions; closures might therefore provide a useable substitute, for instance:
function f = count_call(msg)
calls = 0;
function current_count()
disp(strcat(msg, num2str(calls)));
calls = calls + 1;
end
f = #current_count;
end
In this case, current_count closes over calls (and msg). That way you can express functions that depend on some internal state. You would use it this way:
g = count_call('number of calls: ') % returns a new function ("__init__")
g() % "__call__"
I will be interested to see if this is possible without simply creating a java method in Matlab. I know you can do the following
classdef ExampleObject
properties
test;
end
methods
function exampleObject = ExampleObject(inputTest)
exampleObject.test=inputTest;
end
function f(exampleObject,funcInput)
disp(funcInput+exampleObject.test);
end
end
end
>> e=ExampleObject(5);
>> f(e,10)
15
But as far as my knowledge goes, if you tried to override the call function you'd run into a conflict with Matlab's parenthetical subscript reference subsref. You can find a reference here showing how to overwrite that, and you might be able to get it to do what you want...but it doesn't seem like good form to do so. Not sure how Matlab would handle a call to an object (as opposed to a function) without it getting confused with this.
One way is to override the feval function for your class:
classdef FxnClass < handle
properties
template
end
methods
function obj = FxnClass(t)
obj.template = t;
end
function out = feval(obj, varargin)
out = sprintf(obj.template, varargin{:});
end
end
end
This would be used as:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> feval(f, 3,'two',false)
ans =
x = 3.000000, y = two, z = 0
Now if you want to provide additional syntactic sugar, you could redefine the subsref function for your class as #Salain suggested. Add the following to the previous class definition:
classdef FxnClass < handle
...
methods
function out = subsref(obj, S)
switch S(1).type
case '.'
% call builtin subsref, so we dont break the dot notation
out = builtin('subsref', obj, S);
case '()'
out = feval(obj, S.subs{:});
case '{}'
error('Not a supported subscripted reference');
end
end
end
end
Now you could simply write:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3,'two',false)
ans =
x = 3.000000, y = two, z = 0
Personally I don't particularly like overriding the subsref or subsasgn functions. They are used for too many cases, and its sometimes hard to get them write. For example all the following will eventually call the subsref method with different input:
f(..)
f.template
f.template(..)
f(..).template
f(..).template(..)
There is also the case of the end keyword which could appear in indexing, so you might have to also override it as well in some cases. Not to mention that objects can also be concatenated into arrays, which makes things even more complicated:
>> ff = [f,f];
>> ff(1) % not what you expect!
That said, I think #Frank's suggestion to use nested functions with closures is more elegant in this case:
function f = FxnClass(t)
f = #call;
function out = call(varargin)
out = sprintf(t, varargin{:});
end
end
which is called as before:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3, 'two', false)
If you mean that you want a class to hold a method which you use like a normal function (eg. defined in an m-file), then yes, Matlab does support static methods.
A static method runs independently of any instances of that class, in fact, you don't even need to instantiate a class to use its static methods.
Matlab does not support static fields, however, so you would have to instantiate such a class first, and then set its fields before using the functions (which presumably make use of these fields, since you are asking this question).
Given the limitation with static members, you might be better off with closures, as described by Frank.
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