I have written a simple class in MATLAB to manage a set of key-value pairs. I would like to be able to access the keys using a dot after the object name like:
params.maxIterations
instead of:
params.get('maxIterations')
Is it possible to override the dot operator so that it calls my get() method?
I have tried to override the subsasgn() method as suggested here but I couldn't figure out how I should write it.
You could use dynamic properties. Then instead of adding a list of strings, you add a new property for each 'key'. Get all keys with properties(MyClass) (of just fieldnames(MyClass)
However, I think it's indeed best to overload subsref, but note that doing that properly can eat away the majority of a work week if you do it for the first time...It's not that it's really difficult, it's just that the () operator does so much :)
Luckily, you don't have to. Here's how:
classdef MyClass < handle
methods
function result = subsref(obj, S)
%// Properly overloading the () operator is *DIFFICULT*!!
%// Therefore, delegate everything to the built-in function,
%// except for 1 isolated case:
try
if ~strcmp(S.type, '()') || ...
~all(cellfun('isclass', S.subs, 'char'))
result = builtin('subsref', obj, S);
else
keys = S.subs %// Note: cellstring;
%// could contain multiple keys
%// ...and do whatever you want with it
end
catch ME
%// (this construction makes it less apparent that the
%// operator was overloaded)
throwAsCaller(ME);
end
end % subsref method
end % methods
end % class
Related
I use 16a. I found overloading subsref makes any function calls to an object call (). I am not sure if this is the correct use of subsref. For example,
classdef A < handle
methods
function obj = A(varargin)
end
function v = subsref(obj, S) %#ok<STOUT,INUSD>
assert(false);
end
function c = foo(obj) %#ok<MANU>
c = 1;
end
end
end
Then I god the following errors when using foo.
>> a = A()
a =
A with no properties.
>> a.foo()
Error using A/subsref (line 6)
Assertion failed.
8 assert(false);
If I removed subsref, it works fine. In terms of
http://www.mathworks.com/help/matlab/ref/subsref.html
subsref is called only when A{i}, A(i) or A.field. Since foo is a method, why is subsref still called?
This is completely expected behavior, because to MATLAB, A.field and A.method both use the dot referencing and therefore are processed by subsref. The typical way of getting around this is to instead call your class methods using the standard function call rather than a dot referenced method call.
method(A)
%// Rather than
A.method()
This usage is also superior as it can operate on arrays of objects rather than only scalars. Also, it is more performant.
i have this superClass
classdef SysSignal<handle
%SIGNALP Summary of this class goes here
% Detailed explanation goes here
properties (SetAccess = public, GetAccess = public )
SetOfSignal = containers.Map('KeyType','char', 'ValueType', 'any')
end
methods
%constructor
function sys=SysSignal()
end
function sys=adds(sys,varargin)
%convert form cell to signalup
for n=1:length(varargin)
signal=varargin{1,n};
if isempty(signal.name)
continue
else
%add to the map
sys.SetOfSignal(signal.name)= signal;
end
end
end
and that child class
classdef Signalp<SysSignal
%SIGNALP Summary of this class goes here
% Detailed explanation goes here
properties
name
lineNo
color='red'
sumrole
end
properties (SetAccess=private,GetAccess=public)
arrPrice
LineLength
LineProportion
end
methods
%constructor
function sig=Signalp(varargin)
end
end
end
now i want to change the properties like this:
sys=SysSignal;
s=Signalp;
s.name='dd';
sys.adds(s)
sys.SetOfSignal('dd').sumrole='hello'
but i get that error :
??? Error using ==> subsasgn
Only one level of indexing is supported by a containers.Map.
how can i change the values from the superClass?
The answer is to seperate sys.SetOfSignal('dd').sumrole='hello' into two statements:
dd = sys.SetOfSignal('dd');
dd.sumrole='hello'
That is because sys.SetOfSignal('dd').sumrole doesn't do what you'd intuitively think it does. Indeed the containers.Map class overloads the subscripted reference and subscripted assignment operators. In essence they 'intercepts' the (), {} and . operators at the same time (ie .sumrole is 'sent' to the map.Containers object - instead of your object!). In my opinion that's a really weird design decision but we must live with it!
Have a look at these links for more info:
subsref, subsasgn
gregswiss's answer is correct, except that accessing the containers map creates a copy, so you finish by replacing the old value with the new modified one
dd = sys.SetOfSignal('dd');
dd.sumrole='hello'
sys.SetOfSignal('dd') = dd;
I come from a Java background. I am having issues with classes in Matlab particularly getters and setters. getting a message saying conflict between handle and value class I'm a little lost with what to do so any help for lack of a better word will be helpful.
classdef Person
properties(Access = private)
name;
age;
end
methods
% class constructor
function obj = Person(age,name)
obj.age = age;
obj.name = name;
end
%getters
function name = get.name(obj)
end
function age = get.age(obj)
end
%setters
function value = set.name(obj,name)
end
function value = set.age(obj,age)
end
end
end
Implementation
Since your class is currently a subclass of the default Value class, your setters need to return the modified object:
function obj = set.name(obj,name)
end
function obj = set.age(obj,age)
end
From the documention: "If you pass [a value class] to a function, the function must return the modified object." And in particular: "In value classes, methods ... that modify the object must return a modified object to copy over the existing object variable".
Handle classes (classdef Person < handle) do not need to return the modified object (like returning void):
function [] = set.name(obj,name)
end
function [] = set.age(obj,age)
end
Value vs. Handle
Going a bit deeper, the difference between a Value class and a Handle class lies mostly in assignment:
Assigning a Value class instance to a variable creates a copy of that class.
Assigning a Handle class instance to a variable create a reference (alias) to that instance.
The Mathworks has a good rundown on this topic.
To paraphrase their illustration, the behavior of a Value class is
% p is an instance of Polynomial
p = Polynomial();
% p2 is also an instance of Polynomial with p's state at assignment
p2 = p;
and of a Handle class is
% db is an instance of Database
db = Database();
% db2 is a reference to the db instance
db2 = db;
Quick'n Dirty from the Java perspective:
- "handle" classes are what your mind is set to. proper object instances with pointers to them. use them.
- "value" classes are always returning a full clone of whatever object (which has been modified by what you just did, e.g. setting a name).
the reason they have both in Matlab is that in Matlab you would expect the "value" behaviour natively. Imagine you have a matrix A = [1 2; 3 4], then assign that via B = A. if you now set B(1) = -1 you'd hope that A(1) is still 1, right? this is because matlab keeps track of "copies" and truly creates them as you modify different variables initially set to the same matrix. in OOP you'd have A(1)=-1 now as everythings an object reference.
furthermore, "native" matlab routines dont have a "this/self/me" variable that contains the instance reference to access from within functions. instead, the convention is that the class instance will be prepended to the function's argument list.
so for a function call myclass.mymethod(arg1,arg1), the declaration must be
function mymethod(this, arg1, arg2)
% Note that the name you choose for "this" is arbitrary!
end
mind you, this is the java-perspective (and also my favourite one), the above function call is equivalent to mymethod(myclass,arg1,arg1). this is more native to matlab-style, but somehow makes it harder to see you're calling an objects method.
now, regarding setters/getters: for handle classes, everything feels java-ish now:
classdef MyClass < handle
properties
MyProp;
end
methods
function set.MyProp(this, value) %Note: setMyProp is also valid!
... % do checks etc, trigger calls,
this.MyProp = value;
end
function value = get.MyProp(this)
... % notify, update, triggers etc
value = this.MyProp;
end
end
Of course it goes without saying that you dont need to define a getter if you just want to return the value, i.e. myclassinstance.MyProp will work without any just as well.
Finally, getters/setters for value classes are something that [never encountered me/i never needed] in my 7 years of matlab oop, so my advise would be to go with handle classes and enjoy happy matlab coding :-)
otherwise, the above explanation & official matlab docs is doing the job for value class getter/setters.
Writing a subclass of dynamicprops allows to me to add properties dynamically to an object:
addprop(obj, 'new_prop')
This is great, but I would also love to create set / get functions for these properties on the fly. Or analysis functions that work on these dynamic properties.
My experience with Matlab has been so far, that once I create an instance of a class, adding new methods is not possible. That is very cumbersome, because my object may contain a lot of data, which I'll have to re-load every time that I want to add a new method (because I have to do clear classes).
So is there a way to add methods on the fly?
You cannot add methods like you add dynamic properties. However, there are two ways for implementing new methods during development that won't require you to re-load the data every time.
(1) I write standard methods as separate functions, and call them as myMethod(obj) during development. Once I'm sure they're stable, I add their signature into the class definition file - this requires a clear classes, of course, but it is a much delayed one, and from time to time you may have to shut down Matlab, anyway.
(2) With set/get methods, things are a little trickier. If you are using dynamicprops to add new properties, you can also specify their set/get methods, however (most likely, these methods/functions will want to receive the name of the property so that they know what to refer to):
addprop(obj,'new_prop');
prop = findprop(obj,'new_prop');
prop.SetMethod = #(obj,val)yourCustomSetMethod(obj,val,'new_prop')
EDIT
(2.1) Here's an example of how to set up a hidden property to store and retrieve results (based on jmlopez' answer). Obviously this can be improved a lot if you have a better idea what you're actually designing
classdef myDynamicClass < dynamicprops
properties (Hidden)
name %# class name
store %# structure that stores the values of the dynamic properties
end
methods
function self = myDynamicClass(clsname, varargin)
% self = myDynamicClass(clsname, propname, type)
% here type is a handle to a basic datatype.
self.name_ = clsname;
for i=1:2:length(varargin)
key = varargin{i};
addprop(self, key);
prop = findprop(self, key);
prop.SetMethod = #(obj,val)myDynamicClass.setMethod(obj,val,key);
prop.GetMethod = #(obj)myDynamicClass.getMethod(obj,key);
end
end
function out = classname(self)
out = self.name_;
end
end
methods (Static, Hidden) %# you may want to put these in a separate fcn instead
function setMethod(self,val,key)
%# have a generic test, for example, force nonempty double
validateattributes(val,{'double'},{'nonempty'}); %# will error if not double or if empty
%# store
self.store.(key) = val;
end
function val = getMethod(self,key)
%# check whether the property exists already, return NaN otherwise
%# could also use this to load from file if the data is not supposed to be loaded on construction
if isfield(self.store,key)
val = self.store.(key);
else
val = NaN;
end
end
end
end
I'm adding this answer because I think that this is not intuitive. At least not to myself at this moment. After finding this question I thought I had what I needed to be able to define the set/get methods for my dynamic class. All I wanted to achieve with this was something similar to what python does with its __setattr__ method. In any case, here is a continuation of the class made by #jonas a while ago with a few modifications to add the our custom set method.
classdef myDynamicClass < dynamicprops
properties (Hidden)
name_ %# class name
end
methods
function self = myDynamicClass(clsname, varargin)
% self = myDynamicClass(clsname, propname, type)
% here type is a handle to a basic datatype.
self.name_ = clsname;
for i=1:2:length(varargin)
key = varargin{i};
addprop(self, key);
prop = findprop(self, key);
prop.SetMethod = makefunc(key, varargin{i+1});
end
end
function out = classname(self)
out = self.name_;
end
end
end
function h = makefunc(key, argtype)
h = #newfunc;
function newfunc(obj, val)
obj.(key) = argtype(val);
end
end
With this class I'm defining the set method so that the parameter passed to the attribute is copied to the right type. To see what I mean consider the following usage:
>> p_int = myDynamicClass('Point', 'x', #int8, 'y', #int32);
>> p_int.x = 1000
p_int =
myDynamicClass with properties:
y: []
x: 127
>> class(p_int.x)
ans =
int8
With this we have forced the x attribute to be an integer of 8 bits which can only hold integers from -128 to 127. Also notice how the class of each attribute gives us the intended type.
My experience with Matlab has been so far, that once I create an instance of a class, adding new methods is not possible. That is very cumbersome, because my object may contain a lot of data, which I'll have to re-load everytime that I want to add a new method (because I have to do clear classes).
It's worth noting for present-day readers of this question that this is no longer true. As of MATLAB R2014b MATLAB updates class definitions at the moment you save them, and the behaviour of existing class instances automatically updates accordingly. In the case of adding new methods, this is uncomplicated: the new method simply becomes available to call on class instances even if they were created before the method was added to the class.
The solutions given for choosing set/get methods for dynamic properties still apply.
There are still cases where you might want to add methods to an instance dynamically and the method doesn't constitute a property set/get method. I think the only answer in this case is to assign a function handle as the value to a dynamic property. This doesn't create a bona fide method, but will allow you to call it in the same way you would a method call:
addprop(obj, 'new_method');
obj.new_method = #(varargin) my_method(obj,varargin{:});
Calls to obj.new_method(args) are thus passed to my_method; however this only works with a scalar obj; an array of instances will have separate values for the new_method property so obj.new_method no longer resolves to a single function handle that can be called if obj is an array.
I would like to know if it's possible to use a colon ":" as argument of a function.
Something like that:
function y=func(x)
if x is a colon
do this
else
do that
end
Also is it possible to pass the key work end as argument of a function, and also 1:end, 3:end-5, etc...
I doubt it's possible, but I would like to be sure.
Also, I get a weird error when I pass "1:end" as argument of a function, it produces no error, but inside the function, no argument is assigned (not even the other arguments). Do someone know what happens?
You can override both for your own classes:
classdef MyClass
properties(Access=public)
data
end
methods
function out = end(A,k,n)
disp(A);
disp(k);
disp(n);
out = [];
end
function B = subsref(A,S)
disp(S);
B = [];
end
end
end
As for functions, I never heard of such a functionality.
No, it's not possible to pass a colon as an argument (it doesn't make any sense).