I have some code from a collegue, and I want to add caching to one of the class methods without chancing the original code. I think I should simply overload that function, and call a memoized version of the superclass function. An example:
A.m
classdef A < handle
methods
function res = foo(obj, arg)
disp('class A')
res = arg; % expensive calculation
end
end
end
B.m
classdef B < A
methods
function obj = B()
fn = #foo#A;
obj.foo_m = memoize(fn);
end
function res = foo(obj, arg)
disp('class B')
obj.foo_m(arg)
end
end
end
Now it complains about a an invalid operator in line:
fn = #foo#A;
Furthermore I have the feeling that this might be an issue also: https://stackoverflow.com/a/21413098/1768422
How to solve this in an elegant/transparant way?
Related
classdef Dog
methods
function bark(obj, text)
disp(text)
end
end
end
Suppose d = Dog(). Is there a way to make d("woof") be same as d.bark("woof")? Can the behavior of d() be changed in any other way?
In Python, that's overloading __call__.
subsref controls () behavior.
d(x) passes x to subsref, wrapped inside a struct.
Unpack as x.subs{1} and do anything, including returning an output.
subsref also controls {} and .; redirect these to its native implementation.
MATLAB recommends a mixin class, but that seems overkill.
Thanks to #CrisLuengo for the pointers. If anyone has more info, feel free to share.
classdef Dog
methods
function bark(obj, text)
disp(text)
end
function varargout = subsref(obj, x)
if x(1).type == "()" && length(x) == 1 && ~isempty(x.subs)
[varargout{1:nargout}] = obj.bark(x.subs{1});
else
[varargout{1:nargout}] = builtin('subsref', obj, x);
end
end
end
end
I'm having a weird problem using object oriented matlab, and I'm not sure if I'm completely missing something, or I've hit some unusual behaviour.
I have a superclass defined as follows:
classdef (Abstract) AbstractSimulationData < matlab.mixin.Heterogeneous
properties (Abstract)
name
data
end
properties
timeStamp = -1
end
methods (Abstract)
CalculateData(obj, t)
end
methods
function data = GetData(obj, t)
if obj.timeStamp == t.t
data = obj.data;
else
obj.timeStamp = t.t;
obj.CalculateData(t);
data = obj.data;
end
end
end
end
When the concrete class implements the method CalculateData I intend it to set the superclass property data.
Two concrete classes from this are:
classdef A < AbstractSimulationData
properties
name = 'A'
data = []
end
methods
function obj = A
% No special initialisation
end
function CalculateData(obj, t)
test = t.B.GetData(t)
obj.data = rand(2,10);
end
end
end
And:
classdef B < AbstractSimulationData
properties
name = 'B'
data = containers.Map
end
methods
function obj = B
% No special initialisation
end
function CalculateData(obj, t)
if isempty(obj.data)
obj.data('left') = 1;
obj.data('right') = 2;
end
% Other operations
end
end
end
Within the A.CalculateData method I call the GetData method for B. This in turn calls the B.CalculateData method.
Now, as it filters back up, the data property gets set correctly so that B.GetData returns the value that was set in B.CalculateData.
But, when I go the next step up to A.GetData it returns [], the initialised value. Going through debug mode, the calculations definitely work in A.CalculateData and it seems to set data correctly, but when it jumps back up to the superclass obj.data is the default value from A.
A minimum working example to get this behaviour:
t.B = B();
t.t = 1;
a = A;
a.GetData(t);
>> test =
Map with properties:
Count: 2
KeyType: char
ValueType: any
>> ans =
[]
This is all part of a pretty big project, so it's hard to give the full context, but if it's possible from this, can someone explain why setting superclass data works for B but not A?
If it makes a difference B is returning a container.Map and A is returning 2xn matrix.
As far as I can tell from the documentation, it should work.
Matlab does not allow to define different methods to define multiple constructors with different list of parameters, for instance this will not work:
classdef MyClass
methods
function [this] = MyClass()
% public constructor
...
end
end
methods (Access = private)
function [this] = MyClass(i)
% private constructor
...
end
end
end
But, as illustrated in above example, it is sometimes useful to have private constructors with particular syntax that cannot be called from public interface.
How would you best handle this situation where you need to define both public and private constructors ?
Checking call stack ???
classdef MyClass
methods
function [this] = MyClass(i)
if (nargin == 0)
% public constructor
...
else
% private constructor
checkCalledFromMyClass();
...
end
end
end
methods(Static=true, Access=Private)
function [] = checkCalledFromMyClass()
... here throw an error if the call stack does not contain reference to `MyClass` methods ...
end
end
end
Define a helper base class ???
% Helper class
classdef MyClassBase
methods (Access = ?MyClass)
function MyClassBase(i)
end
end
end
% Real class
classdef MyClass < MyClassBase
methods
function [this] = MyClass()
this = this#MyClassBase();
end
end
methods (Static)
function [obj] = BuildSpecial()
obj = MyClassBase(42); %%% NB: Here returned object is not of the correct type :( ...
end
end
end
Other solution ???
One sneaky trick that I've used to try and work around this limitation is to use another 'tag' class that can only be constructed by MyClass, and then use that to work out which constructor variant you need. Here's a simple sketch:
classdef MyClass
properties
Info
end
methods
function o = MyClass(varargin)
if nargin == 2 && ...
isa(varargin{1}, 'MyTag') && ...
isnumeric(varargin{2}) && ...
isscalar(varargin{2})
o.Info = sprintf('Private constructor tag: %d', varargin{2});
else
o.Info = sprintf('Public constructor with %d args.', nargin);
end
end
end
methods (Static)
function o = build()
% Call the 'private' constructor
o = MyClass(MyTag(), 3);
end
end
end
And
classdef MyTag
methods (Access = ?MyClass)
function o = MyTag()
end
end
end
Note the Access = ?MyClass specifier which means that only MyClass can build instances of MyTag. There's more about using that sort of method attribute in the doc: http://www.mathworks.com/help/matlab/matlab_oop/method-attributes.html
You can have a constructor that accepts multiple syntaxes by taking advantage of varargin:
classdef MyClass
methods (Access = public)
function obj = MyClass(varargin)
% Do whatever you want with varargin
end
end
end
You might, more typically, have some inputs that are required for all syntaxes, and then some optional inputs as well:
classdef MyClass
methods (Access = public)
function obj = MyClass(reqInput1, reqInput2, varargin)
% Do whatever you want with varargin
end
end
end
If you want to have even more control over how things are constructed, I would have a constructor and then also have some public static methods that called the constructor.
For example, let's say I wanted to be able to construct an object either by supplying parameters directly, or by supplying the name of a config file containing parameters:
classdef MyClass
methods (Access = public)
function obj = MyClass(reqInput1, reqInput2, varargin)
% Do whatever you want with varargin
end
end
methods (Static, Access = public)
function obj = fromFile(filename)
myparams = readmyconfigfile(filename);
obj = MyClass(myparams.reqInput1, myparams.reqInput2, ...);
end
end
end
Then you can create an object either with o = MyClass(inputs) or o = MyClass.fromFile(filename).
If you wanted to allow people to construct only from a config file, you could then make the constructor private. And you could add additional public static methods if you wanted to call the constructor in other ways.
In any case, the main point is that the idiomatic way to have a constructor that accepts multiple syntaxes is to take advantage of varargin.
I'd be tempted to go for a modification on your 1st option, but to modify the constructor to have an undocumented "mode" rather than just any input arg.
In the example below I gave that name **private** but you could have anything you want that the end users are unlikely to stumble across....
To be doubly sure you could still check the stack.
function [this] = MyClass(i)
if (nargin == 0)
% public constructor
else
% private constructor
if ischar ( i ) && strcmp ( i, '**private**' )
this.checkCalledFromMyClass();
else
error ( 'MyClass:Consturctor', 'Error calling MyClass' );
end
end
end
end
I have the following class in MATALB.
classdef MyClass
properties
a;
end
methods
function foo(obj)
obj.a = 1;
end
end
end
Now, I do this.
mc = MyClass;
mc.foo();
Now we have this.
mc.a == []
This is something I don't understand. I was expecting
mc.a == [1]
Why hasn't the function foo changed the state of the object?
I am sorry if this is a very basic question. I am used to languages like Java and C#, where the semantics is clearly according to what I'm expecting.
I've discovered that if I do the following, it works are expected.
classdef MyClass < handle
But how to get the desired behavior with a value class in MATLAB (i.e. not a handle class)?
Since a value class is passed by value, not by reference, you need foo to return the updated object:
classdef MyClass
properties
a;
end
methods
function obj = foo(obj)
obj.a = 1;
end
end
end
Then
mc = MyClass;
mc = mc.foo();
This is why I only use handle classes.
I read this documentation page about how to invoke superclass constructor from a child class. The syntax they mention is this:
obj = obj#MySuperClass(SuperClassArguments);
I'm wondering what the purpose of # symbol in the above syntax is. Is the # symbol just a meaningless place occupier in the syntax or does the # symbol represent the function handle symbol in MATLAB?
If I use:
obj = MySuperClass(SuperClassArguments);
instead of
obj = obj#MySuperClass(SuperClassArguments);
it still works fine. So what is the purpose of using # symbol?
1) no this has nothing to do with function handles, this is the syntax used to call the superclass constructor
2) you could try it and see for yourself. Here is an example:
A.m
classdef A < handle
properties
a = 1
end
methods
function obj = A()
disp('A ctor')
end
end
end
B.m
classdef B < A
properties
b = 2
end
methods
function obj = B()
obj = obj#A(); %# correct way
%#obj = A(); %# wrong way
disp('B ctor')
end
end
end
With the correct syntax, we get:
>> b = B()
A ctor
B ctor
b =
B with properties:
b: 2
a: 1
If you use the commented line instead of the first one, you get the following error:
>> clear classes
>> b = B()
A ctor
A ctor
B ctor
When constructing an instance of class 'B', the constructor must preserve the class of the returned
object.
Error in B (line 8)
disp('B ctor')