Suppose I have the following class:
classdef myClass < handle
properties
A = 1
end
methods
function obj = myClass(val)
obj.A = val;
end
end
end
Say I instantiate an instance of this class, then manipulate it slightly and then copy it. As it's a handle class, the "copy" is really just another instance of the same object:
>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> disp(w.A)
15
But I would like to watch A without needing to instantiate myClass. Naively doing
>> value = w.A
doesn't work, since this just copies the value; changning w.A later on will not change value.
Is there a way to provide a "pointer" or "reference" to w.A without having to create a separate handle class? I'd rather keep the notation w.A rather than something like w.A.value (with me having to create the handle class to contain that value).
EDIT: I am using this functionality in order to help encapsulate my code for use with my research lab. I am designing an interface between MATLAB and Arduino to control air and ground vehicles; I was hoping to access stuff like "vehicle.pwmMax", "vehicle.flightCeiling", etc, to encapsulate the underlying object: "vehicle.Globals.pwmMax.value", etc.
You could do this by with a PropertyReference class
classdef PropertyReference < handle
%PropertyReference Reference to a property in another object
properties
sourceHandle
sourceFieldName
end
properties (Dependent = true)
Value
end
methods
function obj = PropertyReference (source, fieldName)
obj.sourceHandle = source;
obj.sourceFieldName = fieldName
end
function value = get.Value( obj )
value = obj.sourceHandle.(obj.sourceFieldName);
end
function set.Value( obj, value )
obj.sourceHandle.(obj.sourceFieldName) = value;
end
function disp( obj )
disp(obj.Value);
end
end
end
Continuing your example, you could then use PropertyReference as follows:
q = myClass(10);
>> q.A = 15;
>> ref = PropertyReference(q,'A');
>> disp(ref)
15
>> q.A = 42;
>> disp(ref)
42
Usage of the PropertyReference class is a bit awkward but the original class remains unchanged.
EDIT - Added disp function overload as per strictlyrude27 comment
I don't think there is anything that will do exactly as you want, given all your constraints.
However, I'm not really clear on your notational issues. Why do you want to retain the notation w.A while you are considered about value not changing? Keeping the notation w.A similar is not a real issue.
Using some modified code, I can produce following execution:
>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A
15
>> value = w.Aref;
>> value()
15
>> w.A = 20;
>> value()
ans =
20
But there is no way around the notation value() as that is the turning point of the implementation; which I think is the closest you can get to what you want. You get the behavior above when you use the following code to implement myClass:
classdef myClass < handle
properties
A = 1;
end
methods
function obj = myClass(val)
obj.A = val;
end
function a = Aref(obj)
a = #()(obj.A);
end
end
end
So you see that the Aref method actually returns a function handle which fetches the value from the object. This also means that this reference is read-only!
Also note that you will have to instantiate a myClass instance before you are able to get the value of A (where would you get the value of A from otherwise?). This instance does not have to be visible inside your current workspace (e.g. another function scope), since the myClass instance is stored within the function handle value.
Drawback of this method is that you only get a read-only reference, you will have to use the call value() to get the actual value instead of the function handle (so that changes the notation, but not the one you wanted to keep (or at least it can be made so by substituting A in my code by Aval and renaming Aref to A). Another drawback is that resolving value might be a bit slower than simply resolving a variable (whether that's a problem will depend on your usage of value()).
If you want some of the notations changed, this can be done by using dependent properties:
classdef myClass < handle
properties (Access=private)
Aval = 1;
end
properties (Dependent)
A;
end
methods
function obj = myClass(val)
obj.A = val;
end
function a = get.A(obj)
a = #()(obj.Aval);
end
function set.A(obj,value)
obj.Aval = value;
end
end
end
The equivalent execution of above is given by:
>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A()
15
>> value = w.A;
>> value()
15
>> w.A = 20;
>> value()
ans =
20
edit: I thought of another way to implement this, which is simpler (i.e. just keep the class of your original post) but it requires you to change the code in other places. The basic idea behind it is the same as the first ones, but without encapsulating it in the object itself (which makes the object cleaner, IMHO).
>> q = myClass(10);
>> q.A = 15;
>> w = q;
>> w.A()
15
>> value = #()(w.A);
>> value()
15
>> w.A = 20;
>> value()
ans =
20
Since you are working with a handle class, both q and w in your example refer to the same object in memory; they are themselves a "pointer"/"reference" to the object they represent.
So continuing your example, if you make changes to one, it will be reflected in the other.
>> q = myClass(10);
>> w = q;
>> q.A = 99;
>> disp(w.A)
99
Also note that you are not creating another instance of the class when you call w = q;. Compare the following examples in terms of memory space:
>> q = myClass(rand(7000));
>> m = memory; disp(m.MemUsedMATLAB)
792870912
>> w = q;
>> m = memory; disp(m.MemUsedMATLAB)
792834048
Against:
>> q = myClass(rand(7000));
>> w = myClass(rand(7000));
??? Error using ==> rand
Out of memory. Type HELP MEMORY for your options.
EDIT
Playing around with this, I came up with the following hackish solution.
First we create a wrapper function around the class constructor. It creates an object as usual, plus it returns a function handle that acts as a read-only accessor to a closure variable synced with the original object property using a "PostSet" events listener.
The only change to the original class is to add the SetObservable property attribute:
myClass.m
classdef myClass < handle
properties (SetObservable)
A
end
methods
function obj = myClass(val)
obj.A = val;
end
end
end
myClassWrapper.m
function [w A] = myClassWrapper(varargin)
w = myClass(varargin{:});
A = #getWA;
%# closure variable
a = w.A;
%# add listener to when w.A changes
addlistener(w, 'A', 'PostSet',#changeCallback);
function val = getWA()
%# return the value of the closure variable
val = a;
end
function changeCallback(obj,ev)
%# update the closure variable
a = ev.AffectedObject.A;
%#fprintf('Value Changed to %g\n',a)
end
end
Now we can use the wrapper as:
>> [w a] = myClassWrapper(10);
>> a()
ans =
10
>> w.A = 99;
>> a()
ans =
99
Related
Take a look at the following minimal working example,
ClassA.m
classdef ClassA < handle
properties
h1 = 0;
h2 = 0;
end
methods
function obj = ClassA(n1,n2)
if nargin == 2
obj.h1 = n1;
obj.h2 = n2;
end
end
end
end
ClassB.m
classdef ClassB < handle
properties
a = ClassA;
a0 = ClassA;
end
methods
function obj = ClassB(n1,n2)
if nargin == 2
obj.a.h1 = n1.h1;
obj.a.h2 = n1.h2;
obj.a0.h1 = n2.h1;
obj.a0.h2 = n2.h2;
end
end
end
end
main.m
h1 = ClassA(1,1);
h2 = ClassA(2,2);
h3 = ClassA(3,3);
h4 = ClassA(4,4);
x01 = ClassB(h1,h2);
x01.a.h1
x01.a.h2
x12 = ClassB(h3,h4);
x01.a.h1 % should keep its value as 1
x01.a.h2 % should keep its value as 2
The problem occurs when I instantiate a second object of class B which causing x01 to be overwritten. I think this has to do with handle class. Is there any clever way to avoid this problem? Notice ClassA must be handle since I need to modify its properties.
Note what is described in the documentation (emphasis mine):
There are two basic approaches to initializing property values:
In the property definition — MATLAB evaluates the expression only once and assigns the same value to the property of every instance.
In a class constructor — MATLAB evaluates the assignment expression for each instance, which ensures that each instance has a unique value.
This means that, for class B, a = ClassA is evaluated only once, and then every object of that class created gets a copy of a. But because ClassA is a handle object, all objects end up pointing to the same object (it is the handle that is copied, not the object).
So, the solution is follow the 2nd method to initialize property values: in the class constructor:
classdef ClassB < handle
properties
a;
a0;
end
methods
function obj = ClassB(n1,n2)
obj.a = ClassA;
obj.a0 = ClassA;
if nargin == 2
obj.a.h1 = n1.h1;
obj.a.h2 = n1.h2;
obj.a0.h1 = n2.h1;
obj.a0.h2 = n2.h2;
end
end
end
end
I want to have a simple static member in a class with simple access i.e I like to have a class_name.static_data instead of class_name.shared_obj.static_data.
I've searched and find the standard method of defining static members in Matlab classes, on mathwork.com as you can see below.
classdef SharedData < handle % an auxiliary class to keep static data
properties
Data1
Data2
end
end
classdef UseData % main class
properties (Constant)
Data = SharedData
end
% Class code here
end
and then we can use it with something like this:
k = UseData
k.Data.Data1=5; % Want to be `k.Data1=5;` instead.
BUT I'm looking to have a top-level static member
( something like
obj_of_UseData.Data1=5;
NOT
obj_of_UseData.Data.Data1=5; )
(i.e. like a top-level member, not second-level one). I seek a method to implement top-level static member , not second-level one.
Thanks
It is possible to follow the advice from the MathWorks related to static data, and still create behavior that makes it look like those variables are members. You can do so by overloading the subsref and subsasgn methods like below. This codes uses the static method way of creating static data, since it is simplest, but the idea translates to the other method, using a handle class, as well.
classdef UseData
properties
Data3
end
methods (Static)
function out = setgetVar(name,value)
persistent data;
if isempty(data)
data = struct('Data1',[],'Data2',[]);
end
if nargin==2
data.(name) = value;
end
out = data.(name);
end
end
methods
function obj = subsref(obj,S)
if isequal(S(1).type,'.')
if strcmp(S(1).subs,'Data1') || strcmp(S(1).subs,'Data2')
obj = UseData.setgetVar(S(1).subs);
return
end
end
obj = builtin('subsref',obj,S);
end
function obj = subsasgn(obj,S,value)
if isequal(S(1).type,'.')
if strcmp(S(1).subs,'Data1') || strcmp(S(1).subs,'Data2')
UseData.setgetVar(S(1).subs,value);
return
end
end
obj = builtin('subsasgn',obj,S,value);
end
end
end
To see it working:
>> x = UseData;
>> y = UseData;
>> x.Data1 = 'bla';
>> y.Data2 = [5,6];
>> x.Data3 = 0;
>> y.Data3 = 10;
>> y.Data1
ans = bla
>> x.Data2
ans =
5 6
>> x.Data3
ans = 0
>> y.Data3
ans = 10
suppose we have following class,i want to declare rational number class in matlab,i am beginner of object oriented programming in matlab languages and i want to learn basics
classdef ratnum %rational number class
properties (Access=protected)
n %numerator
d %denomerator
end
methods
function r=ratnum(numerator,denomenator)
r.n=numerator;
r.d=denomenator;
end
end
end
how can i create constructor with specific values in matlab main part?should i use name of class ?thanks in advance
To instantiate an object of this class you can use: num1 = ratnum(2,3)
Since MATLAB doesn't have method overloading that is based on the amount of passed inputs, you could use nargin to select the correct scenario, as follows:
classdef ratnum %rational number class
properties (Access=protected)
n %//numerator
d %//denominator
end
methods
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%//whatever you want the defaults to be
end
end
end
end
A simple debug trick is to do num1_str=struct(num1) which allows you to see the contents of the object. However, you should create some public methods to get the values (instead of turning the object to a struct every time).
To overload the default summation of MATLAB you need to understand that whenever you write a+b it is automatically translated into plus(a,b). When defining custom classes with custom summation you should make a folder that has the name #classname (in your case #ratnum) and in it:
ratnum.m: the class definition file (which is the code you wrote)
a file named plus.m which looks something like:
.
function sum = plus(ratnum1,ratnum2)
ratnum1 = ratnum(ratnum1);
ratnum2 = ratnum(ratnum2);
sum = (...
ratnum1.r*ratnum2.d + ...
ratnum2.r*ratnum1.d )/ ...
(ratnum1.d * ratnum2.d);
end
Then, when you use + to add ratnums it will use the correct plus function.
Here's some helpful reading: MATLAB Documntation: Implementing Operators for Your Class
To call class methods, even from within other class methods, you must always write the class name first: ratnum.sum(ratnum1). Here's an example:
classdef ratnum %rational number class
properties (Access=public)
n %//numerator
d %//denominator
end
methods (Access = public)
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%whatever you want the defaults to be
end
end
end
methods (Access = public, Static)
function out = sum(ratnum)
out = ratnum.n + ratnum.d;
end
end
end
then:
>> a = ratnum(1,1)
a =
ratnum with properties:
n: 1
d: 1
>> ratnum.sum(a)
ans =
2
If you want to overload constructor with many different forms you'll have to initialize missing parameters with default value (or use varargin for more complex overloads):
function [r] = ratnum(num, den, varargin)
% Showing initializing missing parameters
if (nargin < 2), den = 42; end
if (nargin < 1), num = 7; end
% Showing working with varargin
if (nargin == 3)
...
elseif((nargin > 1) && (ischar(varargin{1}))
...
else
...
end
end
If you want to create named initializers for clarification of their meaning, you'll have to do it with Static methods:
methods (Static)
function [r] = TwoThird()
r = ratnum(2, 3);
end
function [r] = Half()
r = ratnum(1, 2);
end
end
Which can be used like this:
dummy = ratnum.Half(); % Ratio is 1/2
dummy = ratnum.TwoThird(); % Ratio is 2/3
dummy = ratnum(42, 666); % Ratio can be any custom one
I'm grouping a set of anonymous functions into a structure and some variables within that structure. Is there a way to refer 'self', i.e, own structure? What I'd like to accomplish is to have a function returns some values based on the member variables. For simplicity, say I have a struct a, where
a.value_1 = 3;
a.value_2 = 2;
a.sum = #()(self.value_1 + self.value_2)
Is there something like that possible in MATLAB?
Before objected-oriented programming was introduced in MATLAB (including both classdef-style and the obsolete #-directory style classes), one could create lightweight objects using closures and nested functions (lacking inheritance of course). This concept also exists in other languages.
Here is an example:
function s = mystruct()
s = struct('value_1',[], 'value_2',2, 'sum',#mysum);
s.value_1 = 3;
function out = mysum()
out = s.value_1 + s.value_2;
end
end
Which is used as:
>> s = mystruct()
s =
value_1: 3
value_2: 2
sum: #mystruct/mysum
>> s.value_1 = 10; % NOTE: this wont do what you expect!
>> s.sum()
ans =
5
Note that variables are immediately captured when creating a closure (functions have their own private copy if you will). So if you change one of the exposed fields from the returned structure, it will not be reflected in the enclosed state (think of them as read-only properties).
One solution is to provide accessor methods:
function obj = mystruct()
% think of those as private properties
value_1 = 3;
value_2 = 2;
% returned object (this or self)
obj = struct();
% public accessors for properties
obj.value_1 = #accessValue1;
function out = accessValue1(in)
if nargin > 0, value_1 = in; end
out = value_1;
end
obj.value_2 = #accessValue2;
function out = accessValue2(in)
if nargin > 0, value_2 = in; end
out = value_2;
end
% member method
obj.sum = #mysum;
function out = mysum()
out = value_1 + value_2;
end
end
So now we could say:
>> s = mystruct()
s =
value_1: #mystruct/accessValue1
value_2: #mystruct/accessValue1
sum: #mystruct/mysum
>> x = s.value_1(); % get
>> s.value_1(10); % set
>> s.sum()
ans =
12
Which is starting to look like the current recommended approach to create classes:
classdef mystruct < handle
properties
value_1 = 3;
value_2 = 2;
end
methods
function out = sum(obj)
out = obj.value_1 + obj.value_2;
end
end
end
Used in a similar manner:
>> s = mystruct()
s =
mystruct with properties:
value_1: 3
value_2: 2
>> s.value_1 = 10;
>> s.sum
ans =
12
We could also define get/set access methods as before..
This seems to work but I think you should rather create a class than a struct to do this:
a.value_1 = 3;
a.value_2 = 2;
a.sum = #(x)(x.value_1 + x.value_2)
a.sum(a)
With this change
a.value_1 = 3;
a.value_2 = 2;
a.sum = #()(a.value_1 + a.value_2)
Then a.sum() returns 5. But what happens when you change one of the values, later on, e.g., set a.value_1 = 5? Now a.sum() returns ... still 5. The parameters passed into the anonymous function are evaluated upon instantiation. If you want the second behavior to work properly you need to use a class. See my answer to this question for more. The only reason to use a function handle like you have is to avoid evaluating and storing a large output of a function until it's needed.
Being new to MATLAB, I am trying to write a class where, if one of two properties changes value, a third property is automatically recalculated.
It seems events and listeners are made for this, but I just can't get the hang of their basic implementation.
My latest attempt is this
% when property a or b is altered, c will automatically be recalculated
classdef myclass < handle
properties
a = 1;
b = 2;
c
end
events
valuechange
end
methods
function obj = myclass()
addlistener(obj,'valuechange', obj.calc_c(obj))
end
function set_a(obj, input)
obj.a = input;
notify(obj, valuechange)
end
function set_b(obj, input)
obj.b = input;
notify(obj, valuechange)
end
function calc_c(obj)
obj.c = obj.a + obj.b
end
end
end
Which returns following error
Error using myclass/calc_c
Too many output arguments.
Error in myclass (line 18)
addlistener(obj,'valuechange', obj.calc_c(obj))
What am I doing wrong?
Don't you want instead to define c as Dependent, so that every time you use it you are sure that it has been updated?
Something like this
classdef myclass < handle
properties
a
b
end
properties (Dependent)
c
end
methods
function x = get.x(obj)
%Do something to get sure x is consistent
x = a + b;
end
end