Consider the following Matlab (2009a) classes:
classdef BigDeal < handle
properties
hugeness = magic(2000);
end
methods
function self = BigDeal()
end
end
end
classdef BigProxy < handle
properties(Dependent)
hugeness
end
properties(Access = private)
bigDeal
end
methods
function self = BigProxy(bigDeal)
self.bigDeal = bigDeal;
end
function value = get.hugeness(self)
value = self.bigDeal.hugeness;
end
end
end
Now consider the following use of them:
Setup:
>> b = BigDeal
b =
BigDeal handle
Properties:
hugeness: [10x10 double]
Methods, Events, Superclasses
OneLayer:
>> pb = BigProxy(b)
pb =
BigProxy handle
Properties:
hugeness: [10x10 double]
Methods, Events, Superclasses
TwoLayers:
>> ppb = BigProxy(pb)
ppb =
BigProxy handle with no properties.
Methods, Events, Superclasses
Question: Why is my double layered proxy unable to see the hugeness when the single layer can? Dependent properties can be calculated - but does this go only one layer deep for some reason?
Update: See my answer below for workaround.
The problem here is two-fold:
The BigProxy object constructor is designed to accept an input object that has a (non-dependent) hugeness property (like a BigDeal object), which the BigProxy object can then access to compute the value for its own dependent hugeness property.
You are passing a BigProxy object to the BigProxy constructor when you create ppb, and you apparently can't compute a dependent property from another dependent property. For example, this is the error that is thrown when I try to access ppb.hugeness:
??? In class 'BigProxy', the get method for Dependent property 'hugeness'
attempts to access the stored property value. Dependent properties don't
store a value and can't be accessed from their get method.
In other words, the outer BigProxy object tries to compute the value for its dependent hugeness property by accessing the stored value of hugeness for the inner BigProxy object, but there is no stored value since it's a dependent property.
I think the fix for a situation like this would be for the BigProxy constructor to check the type of its input argument to make sure it is a BigDeal object, and throw an error otherwise.
Gnovice provided a good answer to the question "why," thus I awarded him the green check of glory. However, for those wanting a work around, you can do something like this:
classdef BigDeal < handle
properties
hugeness = magic(10000);
end
methods
function self = BigDeal()
end
end
end
classdef BigProxy < handle
properties(Dependent)
hugeness
end
properties(Access = private)
bigDeal
end
methods
function self = BigProxy(bigDeal)
self.bigDeal = bigDeal;
end
function value = get.hugeness(self)
value = self.getHugeness;
end
end
methods(Access = private)
function value = getHugeness(self)
if isa(self.bigDeal,'BigProxy')
value = self.bigDeal.getHugeness;
else
value = self.bigDeal.hugeness;
end
end
end
end
which will allow you to do the following
>> b = BigDeal;
>> pb = BigProxy(b);
>> ppb = BigProxy(pb);
And each of {b,pb,ppb} will all have the same public methods and properties. The only drawback is that I have had to (unnecessarily IMHO) clutter up BigProxy with a new private getter.
Related
So I'm working on a game in Lua and I'm trying to use metatables and classing but I think I'm importing my PHP knowledge and doing things slightly sideways.
-- Basic Monster
Monster = {}
function Monster:new(newX, newY)
local newMonster = {x = newX, y = newY}
setmetatable(newMonster, {__index = Monster})
return newMonster
end
function Monster:moveTo(newX, newY)
self.x = newX
self.y = newY
end
function Monster:takeDamage()
self.hitPoints = self.hitPoints - playerWeapon.damage
if self.hitPoints <= 0 then
self.die()
end
end
function Monster:tap()
self.takeDamage()
end
function Monster:die()
self.removeSelf()
end
--Groblin
Groblin = {}
setmetatable(Groblin, {__index = Monster})
function Groblin:new(newX, newY)
local groblin = display.newImage('assets/images/goblin.png');
groblin.hitPoints = 4
physics.addBody(groblin, 'static')
gameGroup.insert(groblin)
return groblin
end
I'm basically looking to be able to spawn several different types of monsters, and retain some base class functionality for them, but I'm uncertain in the above example how I tie in the base class to the Groblin class I made as I feel like I blew out that subclass altogether by what I'm doing inside of Groblin:new.
If you want classes that you can subclass, try using middleclass. It's not very trivial to do subclasses in standard lua and middleclass has taken care of the boilerplate.
Also, make use of local -- use it anywhere it can be used.
A simple way to do this with your example would be:
function Groblin:new(newX, newY)
local groblin = Monster:new( newX, newY )
setmetatable(groblin, {__index = Groblin})
groblin.image = display.newImage('assets/images/goblin.png');
-- ...
return groblin
end
Use the base class ":new()" method to construct the object and then add the unique fields for the subclass. This insures the base class is properly constructed. Re-setting the metatable to "Groblin" in the subclass constructor insures that any methods defined for the Groblin subclass are called if available, and where the Groblin table does not re-define a method the superclass method will be called.
It probably is better to use a library that provides a consistent approach for object creation and subclassing, but hopefully that gives you a better idea of how to do things manually.
Check out http://www.lua.org/pil/16.2.html for inheritance.
Pay a little attention on the explanation of how the use of self in Account:new works out best while SpecialAccount extends Account.
I generally follow a little different approach than the mentioned in above link. In the above approach -
SpecialAccount = Account:new()
s = SpecialAccount:new{limit=1000.00}
You are calling Account:new() twice, and more problem arises when Acoount:new() does some validaiton on constructor parameters and throws exceptions. For ex: ensuring that the limit passed in non-nil.
So I follow this
SpecialAccount = setmetatable({__index = Account})
Does the trick of allowing superclass constructor to be used in subclasses.
PS: I prefer to treat new function as a constructor. It essentially does the same job.
Let's say I have this class:
classdef abstractGame
%UNTITLED Summary of this class goes here
% Detailed explanation goes here
properties
end
methods (Abstract, Static)
run(gambledAmount);
end
methods (Static)
function init()
gambledAmount = validNumberInput(abstractGame.getGambleString(), 1, 100, 'helpText', 'round');
end
function str = getGambleString()
str = 'How much do you want to gamble?';
end
end
end
And other classes extends from this class. I would like the child classes to redefine the getGambleString method, and for the init-method to use the one the deepest class defines (instead of abstractGame.[...] I want something like calledClass.[...]).
How should I call that?
Thanks in advance.
That is a static virtual function problem; such a construct, though, doesn't exist even in C++, then I suppose there is no chance to have it in matlab. (virtual function definition.)
Btw, in matlab, non-static methods behave as virtual (as in Java), therefore, if you accept not to use static functions, you can obtain the effect you need.
Proof (simplified code):
classdef abstractGame
function str = init(obj)
str = getGambleString(obj);
end
function str = getGambleString(obj)
str = 'How much do you want to gamble?';
end
end
end
classdef game < abstractGame
methods
function str = getGambleString(obj)
str = 'Hi!';
end
end
end
d = game;
d.init()
ans =
Hi!
Confer the following code:
classdef highLowGame
methods(Static)
function [wonAmount, noGuesses] = run(gambledAmount)
noGuesses = 'something';
wonAmount = highLowGame.getPayout(gambledAmount, noGuesses); % <---
end
function wonAmount = getPayout(gambledAmount, noGuesses)
wonAmount = 'something';
end
end
end
Is there a way to call a static method of the same class (inside a static) method without having to write the class name? Something like "self.getPayout(...)" - in case the class turns out to get to 500 lines and I want to rename it.
Not an answer to your question directly, but it's worth noting that you can also put "local functions" after the end of your classdef block in your class.m file, and these behave like private static methods, but you do not need to invoke them using the class name. I.e.
% myclass.m
classdef myclass
methods ( Static )
function x = foo()
x = iMyFoo();
end
end
end
function x = iMyFoo()
x = rand();
end
% end of myclass.m
As far as I can tell, "no" with a "but". In general, you can only specify the static method with the class name. However, you can fake your way around the restriction since MATLAB has feval:
classdef testStatic
methods (Static)
function p = getPi() %this is a static method
p = 3.14;
end
end
methods
function self = testStatic()
testStatic.getPi %these are all equivalent
feval(sprintf('%s.getPi',class(self)))
feval(sprintf('%s.getPi',mfilename('class')))
end
end
end
Here, class(self) and mfilename both evaluate to 'testStatic', so the functions above end up evaluating 'testStatic.getPi'.
Or, alteratively, you can write a non-static method, self.callStatic; then always use that. Inside that, just call testStatic.getPi. Then you'll only need to change that one line.
In Matlab class it seems to be syntactically correct to declare property that is Dependent (computed not stored) and Observable in the same time. Consider code
properties (Access = private)
instanceOfAnotherClass
end
properties (SetAccess = private, Dependent, SetObservable)
propertyTwo
end
methods
function val = get.propertyTwo(this)
val = this.instanceOfAnotherClass.propertyOne;
end
end
Does this work as expected? That is, if the property propertyOne of an object stored in instanceOfAnotherClass is changed is there property change event triggered by propertyTwo? Note that propertyOne is not Observable.
Edit:
It does not work (as I expected). 'PostSet' event is not triggered. So how do I deal with this kind of situation? Is there a better solution then to create propertyTwo as a non Dependent and set it to the same value as 'propertyOne' every time 'propertyOne' changes?
Edit2:
In reaction to Amro's edit of his answer I will explain situation more complex.
Consider this 2 classes:
classdef AClass < handle
properties
a
end
end
classdef BClass < handle
properties (Access = private)
aClassInst
end
properties (Dependent, SetObservable, SetAccess = private)
b
end
methods
function this = BClass(aClass)
this.aClassInst = aClass;
end
function val = get.b(this)
val = this.aClassInst.a;
end
end
end
The class that uses all this code should not get access to AClass. It interacts only with instance of BClass and wants to listen to changes of property b. however if I make property a of AClass observable that would not solve my problem, would it? The 'PostSet' events are not going to propagate to property b, are they?
It might be syntactically correct, but the listener callback will never execute. Example:
classdef MyClass < handle
properties (Access = public)
a
end
properties (SetAccess = private, Dependent, SetObservable)
b
end
methods
function val = get.b(this)
val = this.a;
end
end
end
Now try:
c = MyClass();
lh = addlistener(c, 'b', 'PostSet',#(o,e)disp(e.EventName));
c.a = 1;
disp(c.b)
As you can see the 'PostSet' callback is never executed.
EDIT
The way I see it, SetObservable should really be set on a not b. Its because b is read-only and can only change if a changes. Now the PostSet event would notify us that both properties have changed.
Use the same example I used above, simply move SetObservable from b to a. Of course now you listen to the event as:
lh = addlistener(c, 'a', 'PostSet',#(o,e)disp(e.EventName));
EDIT#2
Sorry I didn't pay attention to the fact that you have composition (BClass has an instance of AClass as private property).
Consider this possible solution:
AClass.m
classdef AClass < handle
properties (SetObservable)
a %# observable property
end
end
BClass.m
classdef BClass < handle
properties (Access = private)
aClassInst %# instance of AClass
lh %# event listener on aClassInst.a
end
properties (Dependent, SetAccess = private)
b %# dependent property, read-only
end
events (ListenAccess = public, NotifyAccess = private)
bPostSet %# custom event raised on b PostSet
end
methods
function this = BClass(aClass)
%# store AClass instance handle
this.aClassInst = aClass;
%# listen on PostSet event for property a of AClass instance
this.lh = addlistener(this.aClassInst, 'a', ...
'PostSet', #this.aPostSet_EventHandler);
end
function val = get.b(this)
val = this.aClassInst.a;
end
end
methods (Access = private)
function aPostSet_EventHandler(this, src, evt)
%# raise bPostSet event, notifying all registered listeners
notify(this, 'bPostSet')
end
end
end
Basically we set property a of AClass as observable.
Next inside the constructor of BClass, we register a listener for the AClass instance passed to listen on property a changes. In the callback we notify listeners of this object that b has changed as well
Since we can't really raise a PostSet manually, I created a custom event bPostSet which we raise in the previous callback function. You can always customize the event data passed, refer to the documentation to see how.
Here is a test case:
%# create the objects
a = AClass();
b = BClass(a);
%# change property a. We will not recieve any notification
disp('a.a = 1')
a.a = 1;
%# now lets listen for the 'bChanged' event on b
lh = addlistener(b, 'bPostSet',#(o,e) disp('-- changed'));
%# try to change the property a again. We shall see notification
disp('a.a = 2')
a.a = 2;
%# remove event handler
delete(lh)
%# no more notifications
disp('a.a = 3')
a.a = 3;
The output was:
a.a = 1
a.a = 2
-- changed
a.a = 3
Notice how we only interact with the BClass instance when we register our listener. Of course since all classes derive from handle class, the instance a and the private property aClassInst both refer to the same object. So any changes to a.a are immediately reflected on b.aClassInst.a, this causes the internal aPostSet_EventHandler to execute, which in turn notify all registered listeners to our custom event.
I have a function that returns a handle to an instantiated object. Something like:
function handle = GetHandle()
handle = SomeHandleClass();
end
I would like to be able to use the return value like I would if I was writing a program in C:
foo = GetHandle().property;
However, I get an error from MATLAB when it tries to parse that:
??? Undefined variable "GetHandle" or class "GetHandle".
The only way I can get this to work without an error is to use a temporary variable as an intermediate step:
handle = GetHandle();
foo = handle.property;
Is there a simple and elegant solution to this, or is this simply impossible with MATLAB's syntax?
To define static properties, you can use the CONSTANT keyword (thanks, #Nzbuu)
Here's one example from MathWorks (with some errors fixed):
classdef NamedConst
properties (Constant)
R = pi/180;
D = 1/NamedConst.R;
AccCode = '0145968740001110202NPQ';
RN = rand(5);
end
end
Constant properties are accessed as className.propertyName, e.g. NamedConst.R. The values of the properties are set whenever the class is loaded for the first time (after the start of Matlab, or after clear classes). Thus, NamedConst.RN will remain constant throughout a session as long as you don't call clear classes.
Hmm, I don't like to disagree with Jonas and his 21.7k points, but I think you can do this using the hgsetget handle class instead of the normal handle class, and then using the get function.
function handle = GetHandle()
handle = employee();
end
classdef employee < hgsetget
properties
Name = ''
end
methods
function e = employee()
e.Name = 'Ghaul';
end
end
end
Then you can use the get function to get the property:
foo = get(GetHandle,'Name')
foo =
Ghaul
EDIT: It is not excactly like C, but pretty close.
The only way to have a static property in MATLAB is as a constant:
classdef someHandleClass < handle
properties (Constant)
myProperty = 3
end
end
then someHandleClass.myProperty will return 3.