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.
Related
I'm facing a problem and studying the OCaml documentation did not enable me to find a satisfying solution yet.
The following snippet illustrates my problem:
class A = object (self)
(* this should not be overwrittable in subclass B, but callable
on objects of type B!
*)
method dangerous_one input =
(do dangerous stuff...)
let safe_output = safe_dangerous_one input in
(... more dangerous things done with safe_output ...)
(* This is safe, should be overwrittable and callable in subclass *)
method safe_dangerous_one input = (...)
end
class B = object(self) inherit A as super
method! safe_dangerous_one input = (* subclass behaviour ... *)
end
To sum up the snippet: class A is base class to subclass B.
It has a dangerous method that is complex and has some dark corners I don't want client code to have to deal with.
In fact, I want to prohibit subclasses from overwriting method "dangerous_one".
Instead, they should overwrite the function "safe_dangerous_one".
Furthermore, it should be possible to CALL "b#dangerous_one" where "b : B" which uses the (new) definition of the "safe_dangerous"-parts as specified in class B.
My dilemma appears to be: if I simply make method "dangerous_one" private, nothing keeps the client code in class B from overwriting it, potentially even making it public.
If I hide its implementation from the signature, it can not be overwritten anymore, but I cannot call "b#dangerous_one" anymore - the code becomes inaccessible to calls also.
Is there any way to achieve what I aim to do?
Best,
Nablezen
If I hide its implementation from the signature, it can not be overwritten anymore, but I cannot call "b#dangerous_one" anymore - the code becomes inaccessible to calls also.
You can, you just need to make it private, you can't hide public methods:
class type safe = object
method safe_dangerous_one : in_channel -> int
end
class a : safe = object (self)
method private dangerous_one input = input_binary_int input
method safe_dangerous_one input =
max 255 (self#dangerous_one input)
end
class b parameters = object(self)
inherit a parameters as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
If you want unsafe method to be accessible, but not overridable, then just re-publish it at another name (kind of NVI):
class type safe = object
method unsafe_dangerous_one : in_channel -> int
method safe_dangerous_one : in_channel -> int
end
class a : safe = object (self)
method private dangerous_one input = input_binary_int input
method unsafe_dangerous_one input = self#dangerous_one input
method safe_dangerous_one input =
max 255 (self#dangerous_one input)
end
class b = object(self)
inherit a as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
And a piece of free advice. In other languages, classes and methods are used as a tool for structuring programs, because they have no better tools. In OCaml you have first class functions, records, structures, etc. So it is better to use a proper tool for at each situation. When you design a class, you should understand, that the method by its original definition (not spoiled by C++/Java/Python/etc) is something overridable. A method is an operation that has an implementation that varies across some genera. So, if you define something as a method, and then trying hard to prevent people from overriding it, then chances are high that you're doing something wrong. If you don't want it to be overridable, then just don't define it as a method at all. In your case you should put dangerous_one operation into a let-bound function. You can bound it in the context of the class, so that you will have an access to all parameters, or you can bind it on a toplevel, the choice is yours:
class a parameters =
let dangerous_one input = input_binary_int input in
object (self)
method safe_dangerous_one input =
max 255 (dangerous_one input)
end
class b = object(self)
inherit a as super
method! safe_dangerous_one input =
super#safe_dangerous_one input + 1
end
Also, a very good source of documentation about OCaml class system is Jason Hickey's Introduction to Objective Caml. It is slightly outdated, but is still very good.
I am developing a MATLAB OOP project for the first time. My parent class will have a very large matrix which the children(many) need to access. How can I prevent the children from duplicating the data ?
In pseudo code I require that,
classdef parent
properties
largeMatrix;
end
end
classdef child < parent
methods
function obj = child(parent)
Data.parent of this child = Share from parent
end
...
something = largeMatrix(n,m);
end
end
p = parent; p.largeMatrix = rand(100);
c1 = child(p);
c2 = child(p);
Both children c1 and c2 should access same data created in the original rand(100), but should not be copying the largeMatrix as I need many children, and would like the program to be memory efficient. The largeMatrix will be read from a file.
PS: This is the first time I am posting in this forum, so do forgive me if I have posted it wrongly.
MATLAB copies the array on write.
Suppose that your parent class is (no need to subclass a handle):
classdef parent
properties
largeMatrix;
end
end
and your child class is:
classdef child < parent
methods
function obj = child(parent)
obj.largeMatrix = parent.largeMatrix;
end
end
end
Now, let's create parent and assign a large matrix to its property largeMatrix:
p = parent;
p.largeMatrix = rand(1e4); % 750 MB circa
Check out the jump in the memory:
Now, let's create a child and check that the data was referenced:
c = child(p);
size(c.largeMatrix)
As you can see no jump in the memory:
Finally, let's make a simple change in the child's data:
c.largeMatrix(1) = 1;
As you can see, only on write the array is effectively copied:
To prevent writes on child.largeMatrix define the property in the parent class with attribute (Abstract = true) and in the child (SetAccess = immutable).
A class is just a data type, it does not hold any data. If you instantiate an object parent of the Parent class, and then an object child of the Child class, then by default child will not inherit any data from parent. You can copy the data from one object to another by using a copy constructor.
child = parent; % this copies the data in `parent` to `child`
However, in this case Matlab creates a copy of the data in parent.
You can avoid copying the data by using handle objects. You can assign the handle object to multiple variables or pass it to functions without causing MATLAB to make a copy of the original object. For example,
classdef A < handle
properties
largeMatrix; % wrap your large data into a handle class
end
end
classdef B
properties
data;
end
methods
function obj = B(mydata)
obj.data = mydata;
end
end
end
Then in the main program you can assign
a = A();
a.largeMatrix = rand(100);
b1 = B(a);
b2 = B(a);
b3 = b1; % can even do this
% no copies of largeMatrix were made, because `a` is a handle object
% accessing largeMatrix
b1.data.largeMatrix
b3.data.largeMatrix
I have a MATLAB class that contains a method that employs a persistent variable. When certain conditions are met I need to clear the persistent variable without clearing the object to which the method belongs. I've been able to do this, but only by employing clear functions which has excessively broad scope for my purposes.
The classdef .m file for this problem:
classdef testMe
properties
keepMe
end
methods
function obj = hasPersistent(obj)
persistent foo
if isempty(foo)
foo = 1;
disp(['set foo: ' num2str(foo)]);
return
end
foo = foo + 1;
disp(['increment foo: ' num2str(foo)]);
end
function obj = resetFoo(obj)
%%%%%%%%%%%%%%%%%%%%%%%%%
% this is unacceptably broad
clear functions
%%%%%%%%%%%%%%%%%%%%%%%%%
obj = obj.hasPersistent;
end
end
end
A script that employs this class:
test = testMe();
test.keepMe = 'Don''t clear me bro';
test = test.hasPersistent;
test = test.hasPersistent;
test = test.hasPersistent;
%% Need to clear the persistent variable foo without clearing test.keepMe
test = test.resetFoo;
%%
test = test.hasPersistent;
test
The output from this is:
>> testFooClear
set foo: 1
increment foo: 2
increment foo: 3
increment foo: 4
set foo: 1
test =
testMe
Properties:
keepMe: 'Don't clear me bro'
Methods
which is the desired output. The problem is that the line clear functions in the classdef file clears all functions in memory. I need a way to clear with a much smaller scope. For example, if hasPersistent' was a function instead of a method, the appropriately scoped clear statement would beclear hasPersistent`.
I know that clear obj.hasPersistent and clear testMe.hasPersistent both fail to clear the persistent variable. clear obj is similarly a bad idea.
Following the discussion in the comments, I think you want to use make foo a private property, accompanied with appropriate increment/reset public functions.
You definitely don't need a persistent variable to implement what you want. But, in any case, to remove a persistent variable from a class method you have to clear the corresponding class. In your case, clear testMe should do what you want.
A related issue is how to clear a persistent variable in a package function. To remove persistent variable myVar from function foo within package foo_pkg you have to do this:
clear +foo_pkg/foo
This should work as long as the parent folder of folder +foo_pkg is in the MATLAB path.
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.
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.