MATLAB: Conditionally define get/set class methods - matlab

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

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

Passing additional iteration-dependent inputs to ode45

I'm trying to solve differential equation using the ode45 function. Consider the following code,
[t1,X2] = ode45(#(t,x)fun(t,x,C1,C2,C3,C4),t0,X01);
where parameters C1, C2, C3 and C4 are column vectors, which should be available to the function that ode45 is referring to (fun.m). I want the values to change after every iteration, so for example, at the beginning the entry of C1 I want in is C1(1), in the next iteration it's C1(2), etc.
How can I implement that?
You may have noticed that the official docs are not too helpful in this scenario (as they pretty much force you to use global variables - which is doable, but discouraged). Instead, I'll show you how this can be done with classes and function handles. Consider the following:
classdef SimpleQueue < handle
%SIMPLEQUEUE A simple FIFO data structure.
properties (Access = private)
data
position
end
methods (Access = public)
function obj = SimpleQueue(inputData)
%SIMPLEQUEUE Construct an instance of this class
obj.data = inputData;
rewind(obj);
end % constructor
function out = pop(obj, howMany)
%POP return the next howMany elements.
if nargin < 2
howMany = 1; % default amount of values to return
end
finalPosition = obj.position + howMany;
if finalPosition > numel(obj.data)
error('Too many elements requested!');
end
out = obj.data(obj.position + 1 : obj.position + howMany);
obj.position = finalPosition;
end % pop
function [] = rewind(obj)
%REWIND restarts the element tracking
% Subsequent calls to pop() shall return elements from the beginning.
obj.position = 0;
end % rewind
end % methods
end % classdef
How to use this? Simple:
C1q = SimpleQueue(C1);
C2q = SimpleQueue(C2);
C3q = SimpleQueue(C3);
C4q = SimpleQueue(C4);
[t1,X2] = ode45(#(t,x)fun(t,x,#C1q.pop,#C2q.pop,#C3q.pop,#C4q.pop),t0,X01);
As you can see, inside fun we use C1q() instead of C1.

Transform equal function handles to other equal function handles

Minimalistic Example:
classdef MyClass
properties
arr
handArr
end
properties(Dependent)
rowAcc
colAcc
end
methods
function obj = MyClass(arr, handRow, handCol)
obj.arr = arr;
obj.handArr{1} = handRow;
if ~isequal(handRow, handCol)
obj.handArr{2} = handCol;
end
end
function r = get.rowAcc(obj)
r = obj.handArr{1}(obj.arr);
end
function c = get.colAcc(obj)
c = obj.handArr{end}(obj.arr);
end
end
end
Now assume I pass equal functions to the constructor, I want the row and col access would also be the same:
f=#(x)#(y) y;
x=MyClass(1, f, f);
isequal(x.rowAcc, x.colAcc) //should be 1
Is this possible?
I have a good reason for this 'insane' requirement:
I have several algorithms which run with 100+ MBs of input and takes those two functions as input, and when they are equal they can be optimized very efficiently; to call the algorithms I need to make transformations to the input functions which are encapsulated inside this class. I can't change the algorithms (not my code) and they use isequal on they're own functions to dispatch.
Two variables pointing to the same anonymous function are considered to be equal
f = #(x)x;
g = f;
isequal(f, g)
% 1
However, if you define the anonymous functions at different times, then they are not considered to be equal because the internal workspaces of the two functions could differ.
f = #(x)x;
g = #(x)x;
isequal(f, g)
% 0
In order to have your property return equal handles, you could have some "shadow" property (accessors_) which caches the accessors and you update these cached values whenever the arr property is changed.
classdef MyClass
properties
arr
handArr
end
properties (Access = 'protected')
accessors_ % An array of accessor functions for rows & columns
end
properties (Dependent)
rowAcc
colAcc
end
methods
function set.arr(obj, value)
% Set the value
obj.arr = value;
% Update the accessors_
self.accessors_ = obj.handArr{1}(obj.arr);
% Only assign another accessor if we have a second one
if numel(obj.handArr) > 1
self.accessors_(2) = obj.handArr{2}(obj.arr);
end
end
function res = get.rowAcc(obj)
res = obj.accessors_(1);
end
function res = get.colAcc(obj)
% If only one was stored, this will return a duplicate of it
res = obj.accessors_(end);
end
end
end
This also has the added benefit that you aren't creating function handles every time that colAcc and rowAcc are retrieved.

How to overload subsref / numArgumentsFromSubscript for functions which have zero output arguments?

I would like to have a class which wraps up a containers.Map. In addition, I want to be able use () indexing to access the sub-map from the parent class, for example:
>> map = containers.Map('Foo', 'Bar');
>> ex = Example(map);
>> ex('Foo')
ans =
Bar
The code for this is below, and it works well. The only problem I am having is with other methods defined on the class. According to the docs, I understand I need to override numArgumentsFromSubscript (somehow?) to help nargout. My crude attempt at simply using numel(obj) as I've seen mentioned online works in most cases, but not when the function you are calling has no output arguments (in which case numel(obj) == 1 ~= 0).
Using the example code below,
>> ex.outGoodbye
ans =
Goodbye
Great! However,
>> ex.sayHello
Error using Example/sayHello
Too many output arguments.
Error in Example/subsref (line 17)
[varargout{1:nargout}] = builtin('subsref', obj, struct);
How can you fix this?
classdef Example
% =====================================================================
properties
map
end
% =====================================================================
methods
% -----------------------------------------------------------------
function obj = Example(map)
obj.map = map;
end
% -----------------------------------------------------------------
function varargout = subsref(obj, struct)
if strcmp(struct(1).type, '()')
[varargout{1:nargout}] = builtin('subsref', obj.map, struct);
else
[varargout{1:nargout}] = builtin('subsref', obj, struct);
end
end
% -----------------------------------------------------------------
function n = numArgumentsFromSubscript(obj, struct, indexingContext)
n = numel(obj); % Necessary to overload subsref - for some reason
end
% -----------------------------------------------------------------
function obj = subsasgn(obj, struct, varargin)
if strcmp(struct(1).type, '()')
obj = builtin('subsasgn', obj.map, struct, varargin{:});
obj = Example(obj);
else
obj = builtin('subsasgn', obj, struct, varargin{:});
end
end
% -----------------------------------------------------------------
function sayHello(obj)
disp('Hello'); % nargout == 0. Does NOT work
end
% -----------------------------------------------------------------
function out = outGoodbye(obj)
out = 'Goodbye'; % nargout > 0. Works
end
% -----------------------------------------------------------------
end
% =====================================================================
end
So digging into this a little further, you have a few options for how to get around this behavior.
method(obj) Calling Convention
You could simply change the way that you're calling the class method. Instead of using the dot notation, you could simply use the standard function notation.
sayHello(ex)
%// vs.
ex.sayHello()
This will avoid calling subsref when calling a method. Also, this is actually the fastest way to call a method of a class in the current iteration of MATLAB's OOP. Additionally, this would require no changes to your current code.
Use nargout to determine number of method outputs
Another option is to add a special case in subsref or numArgumentsFromSubscript that looks for methods called using the dot notation. Then you can explicitly determine the number of output arguments of the method using the following call to nargout.
nArgs = nargout('classname>classname.methodname');
Then you would use that rather than numel(obj). This could be implemented in either numArgumentsFromSubscript or subsref.
numArgumentsFromSubscript
function n = numArgumentsFromSubscript(obj, struct, indexingContext)
%// Check if we are calling obj.method
if strcmp(struct(1).type, '.') && ...
ischar(struct(1).subs) && ismember(struct(1).subs, methods(obj))
%// Determine the package (if any)
cls = class(obj);
parts = regexp(cls, '\.', 'split');
%// Import the package (if any) just into the namespace of this method
if numel(parts) > 1
import(cls);
end
%// Determine number of outputs for this method
n = nargout(sprintf('%s>%s.%s', parts{[end end]}, struct(1).subs));
else
%// Default to numel(obj)
n = numel(obj);
end
end
subsref
function varargout = subsref(obj, struct)
if strcmp(struct(1).type, '()')
[varargout{1:nargout}] = builtin('subsref', obj.map, struct);
%// Check if we are calling obj.method
elseif strcmp(struct(1).type, '.') && ...
ischar(struct(1).subs) && ismember(struct(1).subs, methods(obj))
%// Determine the package (if any)
cls = class(obj);
parts = regexp(cls, '\.', 'split');
%// Import the package (if any) just into the namespace of this method
if numel(parts) > 1
import(cls);
end
%// Determine number of outputs for this method
nout = nargout(sprintf('%s>%s.%s', parts{[end end]}, struct(1).subs));
%// Call builtin subsref with this number of outputs
[varargout{1:nout}] = builtin('subsref', obj, struct);
else
[varargout{1:nargout}] = builtin('subsref', obj, struct);
end
end
Summary
subsref is a pain and a lot of times you end up with a lot of logic to determine what is being called and you'll be right only about 80% of the time. I think that the first approach is the most straightforward, would likely be the most performant (you skip all of the checks in subsref) and deals better with arrays of objects.
If you really wanted to keep the obj.method notation, I would probably recommend changing numArgumentsFromSubscript (rather than subsref) to keep the number of output argument stuff in one place.
Update
Based upon your feedback that the nargout trick doesn't work in cases where the class is contained within a package (foo.bar.Example). I have added a workaround to the above examples. The trick is to call import('foo.bar.Example') prior to calling nargout('Example>Example.sayHello').

Matlab property that automatically updates

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