Matlab property that automatically updates - matlab

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

Related

How do I write a common set method for multiple properties in MATLAB

I work within a project which has several classes which define properties that use essentially the same set method. To make the code more readable, I want to implement a commonSetter method. The overall goal is to include this commonSetter method in the superclass, so that all the classes could use it.
The question was already posted here, but unfortunately, the answer is not working. I changed the code to the following, but get the error: Maximum recursion limit of 500 reached.
classdef MyClass
properties
A
B
end
methods
function mc = MyClass(a,b) % Constructor
mc.A = a;
mc.B = b;
end
function mc = set.A(mc, value) % setter for A
mc = mc.commonSetter(value, 'A');
end
function mc = set.B(mc, value) % setter for B
mc = mc.commonSetter(value, 'B');
end
end
methods(Access = protected)
function mc = commonSetter(mc, value, property)
% do some stuff
disp('Made it into the commonSetter!')
mc.(property) = value;
end
end
end
So far I know that there is an infinite loop where mc.(property) = value; calls set.A (or set.B), which in turn calls commonSetter.
In my post # MathWorks the following was suggested:
To break that loop I guess you should look at builtin() and subsasgn(). Maybe Overriding subsref and subsasgn - effect on private properties can be of some help.
Currently, I have troubles realizing the suggestions and additionally not very comfortable to overwrite subsasgn() as I'm not sure how it will affect the overall project. I would like to know, if someone has other ideas or knows how to overwrite subsasgn() safely.
To solve the recursion error, you could just let the commonSetter method output the new value instead of the object.
classdef MyClass
properties
A
B
end
methods
function mc = MyClass(a, b)% Constructor
mc.A = a;
mc.B = b;
end
function mc = set.A(mc, value)% setter for A
mc.A = mc.commonSetter(value, 'A'); % update mc.A
end
function mc = set.B(mc, value)% setter for B
mc.B = mc.commonSetter(value, 'B');
end
end
methods (Access = protected)
function new_value = commonSetter(mc, value, property) % only return the new value
% do some stuff
disp('Made it into the commonSetter!')
if value > 5
new_value = -10;
else
new_value = value;
end
end
end
end

Automatic change values, in instance of class, by event

I would like to create a class that (for simplicity) adds two numbers as soon as I change an input parameter in an instance of the class. For simplicity I have created this class:
classdef test < handle
properties (Constant)
privatNummer = 10;
end
properties
brugerNummer;
sum;
end
methods
function obj = test()
obj.sum = method1(obj);
end
function obj = method1(obj)
obj.sum = obj.brugerNummer + obj.privatNummer;
end
end
end
How do I get it to automatically update obj.sum when I give it a new value? Currently I have to run obj.method1 every time I want to update obj.sum.
I have tried something like this (but I just can't get it working):
classdef test < handle
properties (Constant)
privatNummer = 10;
end
properties
brugerNummer;
sum;
end
methods
function obj = test()
notify(obj,'StateChange')
obj.sum = method1(obj);
addlistener(obj.brugerNummer,'Ændret nummer',#RespondToToggle.method1);
end
function src = method1(src)
src.sum = src.brugerNummer + src.privatNummer;
end
end
events
StateChange
end
end
I developed two solutions for the problems. The first relying on Dependent properties, setters and getters; the second relying on listeners and callback-functions.
First Solution:
classdef test
properties (Constant)
privatNummer = 10;
end
properties
brugerNummer;
end
properties (Dependent)
sum;
end
methods
function obj = test()
% Constructor
end
function value = get.sum(obj)
value = obj.brugerNummer + obj.privatNummer;
end
end
end
Second Solution (this was a real hassle):
classdef test < handle
properties (Constant)
privatNummer = 10;
end
properties (SetObservable)
brugerNumber;
end
properties
sum;
end
methods
function obj = test()
% constructor
addlistener(obj, 'brugerNumber', 'PostSet',#test.callbackFun);
end
end
methods (Static)
function callbackFun(~,evnt)
obj = evnt.AffectedObject;
obj.sum = obj.brugerNumber + obj.privatNummer;
end
end
end

Function with input type double in classdef

I am starting with oop in Matlab and seem to miss something.
classdef car < handle
properties (Access = public)
a
b
end
methods
function obj = update(obj)
obj.b = updateB(obj.a, obj.b);
end
function B = updateB(a, b)
B = a + b;
end
end
end
I get the famous Undefined function 'updateB' for input arguments of type 'double'. error every time, I try to call the function update. Oddly, it works if I change updateB to:
function B = updateB(obj)
B = obj.a + obj.b;
end
What am I missing? I do not always want to call updateB with obj, because I want to use the function without using the actual object's properties.
When, if you don't want the method to rely on a specific instance, use this approach:
methods
function obj = update(obj)
obj.b = car.updateB(obj.a, obj.b);
end
end
methods (Static)
function B = updateB(a, b)
B = a + b;
end
end

MATLAB: Conditionally define get/set class methods

I have created some MATLAB classes to do some error-checking when I use certain types of structures. This improve development time by preventing errors in the code, but significantly slow down execution time.
One way to get around this is to comment out the set methods inside the class. Is it possible to do this programmatically? For example, only define these methods if a parameter in the constructor is true.
classdef MWE
%MWE Minimum working example
properties
A
B
C
end
methods
function obj = MWE(A, B, C)
if nargin ~= 3
error('A, B and C must all be provided.');
end
obj.A = A;
obj.B = B;
obj.C = C;
end
% function obj = set.A(obj, value)
% validate(obj, value, 'A');
% obj.A = value;
% end
%
% function obj = set.B(obj, value)
% validate(obj, value, 'B');
% obj.B = value;
% end
%
% function obj = set.C(obj, value)
% validate(obj, value, 'C');
% obj.C = value;
% end
end
methods (Access = private)
function validate(obj, value, name)
% Code here
end
end
end
Is it possible to do this programmatically? For example, only define these methods if a parameter in the constructor is true.
After some discussion, I see there are different ways of looking at your question. And, indeed, it may be that you cannot do what you are asking as interpreted by some. Here are two cases, however, that may suffice.
Case 1
You have computationally intensive or otherwise time consuming methods, that you use to "do some error-checking", in a development setting, but want to turn off in a production environment. And, these checks occur when the class is instantiated.
Place these methods in a wrapper function that is called from the constructor.
Here's an example
classdef classFoo
properties(Access=private)
fbar;
end
methods
function this = classFoo(arg1, argN, debugMode)
if(nargin>2 && debugMode)
if(~this.verifyStuff(arg1, argN))
throw(MException('classFoo:ConstructFailure','Could not verify'));
else
this.fbar = timeConsumingFunction();
end
else
this.fbar = 42; % defaultValue;
end
% continue construction
end
function didVerify = verifyStuff(this, varargin)
% complex code
didVerify = randi(2)-1; % 50/50
end
end
end
Then when creating objects you can choose to pass the debug mode flag as true like this:
a=classFoo(1,2,true)
or as false, like this:
a=classFoo(1,2,false)
or not at all, which is the same as the false case, like this:
a=classFoo(1,2)
Case 2
You have two different versions of a get/set method that you are commenting out depending on your development environment.
Add a private member parameter (e.g. isDebugging) and set it at time of construction. Now, instead of commenting out code in your get and set methods, you can handle the different cases with a simple if/else, predicated on your debug state like this:
classdef classFoo
properties(Access=private)
fbar;
isDebugging;
end
methods
function this = classFoo(debugMode)
if(nargin<1 || ~islogical(debugMode))
debugMode = false;
end
this.isDebugging = debugMode;
end
function setfbar(this, fIn)
if(this.isDebugging)
this.fbar = timeConsumingFunction(fIn);
else
this.fbar = fIn; % defaultValue;
end
end
end
end

How to get A Dependent Property depending on properties of objects of different class in Matlab

See the code below:
Ex_ObjA.m
classdef Ex_ObjA
properties
a
end
methods
function Obj=Ex_ObjA(t)
Obj.a = t;
end
end
end
Ex_ObjBC.m
classdef Ex_ObjBC
properties
b
end
properties (Dependent = true, SetAccess = public)
c
end
methods
function Obj=Ex_ObjBC(t)
Obj.b = t;
end
function c=get.c(Obj,s1) % error: Get methods must have exactly one input
c = Obj.b + s1.a;
end
end
end
I tried to do following:
s1 = Ex_ObjA(2);
s2 = Ex_ObjBC(3);
s2.c
Not successful, because "Get methods must have exactly one input". So I can pass the s1.a to Ex_ObjBC to get s1.c?
c isn't really a Dependent property, it's the result of a calculation. Just get rid of the property c, and have a method c = calculatec(Obj, s1) that executes the same code as you have now.