How can I write generalized functions to manipulate private properties? - oop

In Matlab, I would like to perform some operations on private members of a class. I would also like to perform this exact same task on other classes as well. The obvious solution is to write a function in a separate M file that all the classes call in order to perform this task. However, that seems impossible in Matlab (see below). Is there another way to accomplish this?
Here is the problem specifically: suppose I have one m file with the contents
classdef PrivateTest
properties (Access=private)
a
end
methods
function this = directWrite(this, v)
this.a = v;
end
function this = sameFileWrite(this, v)
this = writePrivate(this, v);
end
function this = otherFileWrite(this, v)
this = otherFileWritePrivate(this, v);
end
function print(this)
disp(this.a);
end
end
end
function this = writePrivate(this, v)
this.a = v;
end
...and another m file with the contents
function this = otherFileWritePrivate(this, v)
this.a = v;
end
After instantiating p = PrivateTest, both of these commands work fine (as expected):
p = p.directWrite(1);
p = p.sameFileWrite(2);
...but this command doesn't work even though it's the same code, just in a different m file:
p = p.otherFileWrite(3);
So, it seems like any code that performs operations on private properties of a class MUST be in the same m file as the classdef that defines those private properties. Another possibility might be to have all the classes inherit a class with the writing method, but Matlab doesn't allow this either. In one m file, I would have this code:
classdef WriteableA
methods
function this = inheritWrite(this, v)
this.a = v;
end
end
end
...and in another m file I would have this code:
classdef PrivateTestInherit < WriteableA
properties (Access=private)
a
end
end
However, after instantiating p = PrivateTestInherit;, the command p.inheritWrite(4) causes the same error message as before: "Setting the 'a' property of the 'PrivateTestInherit' class is not allowed."
In light of this, How is it possible to generalize code that manipulates private properties in Matlab, or is it possible?

It is not possible to manipulate private properties outside of the class, that is why they are called private. This idea is called encapsulation.
You can in solve it in many ways:
Define public property that wraps the private, and change it. (See code below)
(Inheritance pattern) Do a common father class, your other classes inherit the function
classdef PrivateTest
properties (Access=private)
a
end
properties(Access=public,Dependent)
A
end
methods
function this = set.A(this,val)
this.a = val;
end
function val = get.A(this)
val = this.a;
end
function this = directWrite(this, v)
this.a = v;
end
function this = sameFileWrite(this, v)
this = writePrivate(this, v);
end
function this = otherFileWrite(this, v)
this = otherFileWritePrivate(this, v);
end
function print(this)
disp(this.a);
end
end
end
function this = writePrivate(this, v)
this.A = v;
end

Related

Lua inheritance and methods

How to inherit a new class player from class actor and make method actor:new(x, y, s) called in method player:new(x, y, s) with the same parameters. I need to make player:new the same but with additional parameters so the player can have more properties than actor.
Is there a way to do this not only in new method, but in other methods, like player:move(x, y) will call actor:move(x, y) or self:move(x, y) but with additional code?
I use this pattern to make classes in modules:
local actor = {}
function actor:new(x, y, s)
self.__index = self
return setmetatable({
posx = x,
posy = y,
sprite = s
}, self)
end
-- methods
return actor
A good way to do this is to have a separate function that initializes your instance. Then you can simply call the base classes initialization within the inherited class.
Like in this example: http://lua-users.org/wiki/ObjectOrientationTutorial
function CreateClass(...)
-- "cls" is the new class
local cls, bases = {}, {...}
-- copy base class contents into the new class
for i, base in ipairs(bases) do
for k, v in pairs(base) do
cls[k] = v
end
end
-- set the class's __index, and start filling an "is_a" table that contains this class and all of its bases
-- so you can do an "instance of" check using my_instance.is_a[MyClass]
cls.__index, cls.is_a = cls, {[cls] = true}
for i, base in ipairs(bases) do
for c in pairs(base.is_a) do
cls.is_a[c] = true
end
cls.is_a[base] = true
end
-- the class's __call metamethod
setmetatable(cls, {__call = function (c, ...)
local instance = setmetatable({}, c)
-- run the init method if it's there
local init = instance._init
if init then init(instance, ...) end
return instance
end})
-- return the new class table, that's ready to fill with methods
return cls
end
You would simply do:
actor = CreateClass()
function actor:_init(x,y,s)
self.posx = x
self.posy = y
self.sprite = s
end
player = CreateClass(actor)
function player:_init(x,y,s,name)
actor.init(self, x,y,s)
self.name = name or "John Doe"
end

Why can't I use builtin for classes that overload subsref?

I would like to overload only one type of subsref calls (the '()' type) for a particular class and leave any other calls to Matlab's built in subsref -- specifically, I want Matlab to handle property/method access via the '.' type. But, it seems like Matlab's 'builtin' function doesn't work when subsref is overloaded in a class.
Consider this class:
classdef TestBuiltIn
properties
testprop = 'This is the built in method';
end
methods
function v = subsref(this, s)
disp('This is the overloaded method');
end
end
end
To use the overloaded subsref method, I do this:
t = TestBuiltIn;
t.testprop
>> This is the overloaded method
That's as expected. But now I want to call Matlab's built in subsref method. To make sure I'm doing things right, first I try out a similar call on a struct:
x.testprop = 'Accessed correctly';
s.type = '.';
s.subs = 'testprop';
builtin('subsref', x, s)
>> Accessed correctly
That's as expected as well. But, when I try the same method on TestBuiltIn:
builtin('subsref', t, s)
>> This is the overloaded method
...Matlab calls the overloaded method rather than the built in method. Why does Matlab call the overloaded method when I requested that it call the builtin method?
UPDATE:
In response to #Andrew Janke's answer, that solution almost works but doesn't quite. Consider this class:
classdef TestIndexing
properties
prop1
child
end
methods
function this = TestIndexing(n)
if nargin==0
n = 1;
end
this.prop1 = n;
if n<2
this.child = TestIndexing(n+1);
else
this.child = ['child on instance ' num2str(n)];
end
end
function v = subsref(this, s)
if strcmp(s(1).type, '()')
v = 'overloaded method';
else
v = builtin('subsref', this, s);
end
end
end
end
All of this works:
t = TestIndexing;
t(1)
>> overloaded method
t.prop1
>> 1
t.child
>> [TestIndexing instance]
t.child.prop1
>> 2
But this doesn't work; it uses the built in subsref for the child rather than the overloaded subsref:
t.child(1)
>> [TestIndexing instance]
Note that the above behavior is inconsistent with both of these behaviors (which are as expected):
tc = t.child;
tc(1)
>> overloaded method
x.child = t.child;
x.child(1)
>> overloaded method
It's possible, IIRC. To change () but not {} and '.', write your subsref method to pass those other cases along to the builtin subsref from within your overloaded subsref, instead of trying to explicitly call the builtin from outside.
function B = subsref(A, S)
% Handle the first indexing on your obj itself
switch S(1).type
case '()'
B = % ... do your custom "()" behavior ...
otherwise
% Enable normal "." and "{}" behavior
B = builtin('subsref', A, S(1))
end
end
% Handle "chaining" (not sure this part is fully correct; it is tricky)
orig_B = B; % hold on to a copy for debugging purposes
if numel(S) > 1
B = subsref(B, S(2:end)); % regular call, not "builtin", to support overrides
end
end
(And if that builtin call doesn't work, you can just put in cases that use . and {} directly, because the subsref overload is ignored inside the class definition.)
To make it fully functional, you may need to change B to a varargout, and add chaining behavior in to the "()" case.
To expand on the explanation given on the Mathworks board, builtin only works from within an overloaded method to access the pre-existing (built in) method.
Overloading a method in Matlab effectively shadows the built in implementation from everything except the method doing the shadowing, and the method doing the shadowing must use builtin to access the built in implementation instead of recursing into itself.
In general. You should use builtin(m,s) inside the function that is been overloaded. This is specified clearly in MATLAB documentation.
http://www.mathworks.com/help/matlab/ref/builtin.html
builtin(function,x1,...,xn) executes the built-in function with the
input arguments x1 through xn. Use builtin to execute the original
built-in from within a method that overloads the function. To work
properly, you must never overload builtin.
Consider this code:
classdef TestBuiltIn
properties
testprop = 'This is the built in method';
testprop2 = 'This is the derived subsref ';
end
methods
function v = subsref(m, s)
disp('enter subsref no matter how!');
v = builtin('subsref',m, s);
end
end
end
and test command
clear;
t = TestBuiltIn;
builtin('subsref', t, s)
s.type = '.';
s.subs = 'testprop';
s2 = s;
s2.subs = 'testprop2';
>> builtin('subsref', t, s1)
enter subsref no matter how!
ans =
This is the derived subsref
>> builtin('subsref', t, s)
enter subsref no matter how!
ans =
This is the built in method
In your updated version of this problem, when you call t.child(1), the subsref function will receive argument s with s(1).type='.', s(1).subs='child' and s(2).type='()', s(2).subs='1'. The evaluation of this expression is not in a step-by-step manner, as Andrew Janke mentioned in his answer. As a result, when overriding subsref, you should handle this operation chain, by first processing the '.' operator. Here is a incomplete example for your case,
function v = subsref(this, s)
switch s(1).type
case '.'
member = s(1).subs;
if ismethod(this, member)
% invoke builtin function to access method member
% there is issue about the number of output arguments
v = builtin('subsref',this,s);
elseif isprop(this, member) % property
if length(s) == 1
% invoke builtin function to access method member
v = builtin('subsref', this, s);
elseif length(s) == 2 && strcmp(s(2).type,'()')
% this is where you evaluate 'tc.child(1)'
else
% add other cases when you need, otherwise calling builtin
end
else
% handling error.
end
case '()'
% this is where you evaluate 't(1)'
% you may need to handle something like 't(1).prop1', like the '.' case
otherwise
% by default, calling the builtin.
end
end
You can also find a detailed code sample and instruction at Code Patterns for subsref and subsasgn Methods.
One more thing you may need to know, is that method members in this class will also be invoked through subsref with '.' operation. Look at this subject subsref on classes: how to dispatch methods?, you will find that the builtin function has no return value (since the invoked method has no return value). However, the return value of builtin is assigned to v(even though v is replaced by varargout), which is an obvious error. The author also gives a temporary solution by using try ... catch to resolve this error.

Does MATLAB support "callable" (i.e. function-like) classes?

Is it possible to define a MATLAB class such that the objects from this class can be called like any other function?
IOW, I'm asking whether one can write in MATLAB the equivalent of something like the following Python class:
# define the class FxnClass
class FxnClass(object):
def __init__(self, template):
self.template = template
def __call__(self, x, y, z):
print self.template % locals()
# create an instance of FxnClass
f = FxnClass('x is %(x)r; y is %(y)r; z is %(z)r')
# call the instance of FxnClass
f(3, 'two', False)
...
[OUTPUT]
x is 3; y is 'two'; z is False
Thanks!
I do not know, whether MATLAB directly supports what you want, but MATLAB does support first-class functions; closures might therefore provide a useable substitute, for instance:
function f = count_call(msg)
calls = 0;
function current_count()
disp(strcat(msg, num2str(calls)));
calls = calls + 1;
end
f = #current_count;
end
In this case, current_count closes over calls (and msg). That way you can express functions that depend on some internal state. You would use it this way:
g = count_call('number of calls: ') % returns a new function ("__init__")
g() % "__call__"
I will be interested to see if this is possible without simply creating a java method in Matlab. I know you can do the following
classdef ExampleObject
properties
test;
end
methods
function exampleObject = ExampleObject(inputTest)
exampleObject.test=inputTest;
end
function f(exampleObject,funcInput)
disp(funcInput+exampleObject.test);
end
end
end
>> e=ExampleObject(5);
>> f(e,10)
15
But as far as my knowledge goes, if you tried to override the call function you'd run into a conflict with Matlab's parenthetical subscript reference subsref. You can find a reference here showing how to overwrite that, and you might be able to get it to do what you want...but it doesn't seem like good form to do so. Not sure how Matlab would handle a call to an object (as opposed to a function) without it getting confused with this.
One way is to override the feval function for your class:
classdef FxnClass < handle
properties
template
end
methods
function obj = FxnClass(t)
obj.template = t;
end
function out = feval(obj, varargin)
out = sprintf(obj.template, varargin{:});
end
end
end
This would be used as:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> feval(f, 3,'two',false)
ans =
x = 3.000000, y = two, z = 0
Now if you want to provide additional syntactic sugar, you could redefine the subsref function for your class as #Salain suggested. Add the following to the previous class definition:
classdef FxnClass < handle
...
methods
function out = subsref(obj, S)
switch S(1).type
case '.'
% call builtin subsref, so we dont break the dot notation
out = builtin('subsref', obj, S);
case '()'
out = feval(obj, S.subs{:});
case '{}'
error('Not a supported subscripted reference');
end
end
end
end
Now you could simply write:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3,'two',false)
ans =
x = 3.000000, y = two, z = 0
Personally I don't particularly like overriding the subsref or subsasgn functions. They are used for too many cases, and its sometimes hard to get them write. For example all the following will eventually call the subsref method with different input:
f(..)
f.template
f.template(..)
f(..).template
f(..).template(..)
There is also the case of the end keyword which could appear in indexing, so you might have to also override it as well in some cases. Not to mention that objects can also be concatenated into arrays, which makes things even more complicated:
>> ff = [f,f];
>> ff(1) % not what you expect!
That said, I think #Frank's suggestion to use nested functions with closures is more elegant in this case:
function f = FxnClass(t)
f = #call;
function out = call(varargin)
out = sprintf(t, varargin{:});
end
end
which is called as before:
>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3, 'two', false)
If you mean that you want a class to hold a method which you use like a normal function (eg. defined in an m-file), then yes, Matlab does support static methods.
A static method runs independently of any instances of that class, in fact, you don't even need to instantiate a class to use its static methods.
Matlab does not support static fields, however, so you would have to instantiate such a class first, and then set its fields before using the functions (which presumably make use of these fields, since you are asking this question).
Given the limitation with static members, you might be better off with closures, as described by Frank.

Matlab: Convert superclass to subclass object

I want to create a subclass, ess say, to the built-in ss class. I'd like to be able to convert an existing ss object to an ess object and at the same time add the missing properties, e.g. w, by something like this
sys=ss(a,b,c,d);
esys=ess(sys,w);
but I can't figure out how to setup the constructor correctly. What is the best way to achieve this? My code currently looks like this
classdef ess < ss
properties
w
end
methods
function obj = ess(varargin)
if nargin>0 && isa(varargin{1},'StateSpaceModel')
super_args{1} = sys;
else
super_args = varargin;
end
obj = obj#ss(super_args{:});
end
end
end
But this does not work as I get the following error:
>> ess(ss(a,b,c,d))
??? When constructing an instance of class 'ess', the constructor must preserve
the class of the returned object.
Of course I could copy all the object properties by hand but it seems to me that there should be some better way.
Here is an example of what I had in mind:
classdef ss < handle
properties
a
b
end
methods
function obj = ss(varargin)
args = {0 0}; %# default values
if nargin > 0, args = varargin; end
obj.a = args{1};
obj.b = args{2};
end
end
end
and:
classdef ess < ss
properties
c
end
methods
function obj = ess(c, varargin)
args = {};
if nargin>1 && isa(varargin{1}, 'ss')
args = getProps(varargin{1});
end
obj#ss(args{:}); %# call base-class constructor
obj.c = c;
end
end
end
%# private function that extracts object properties
function props = getProps(ssObj)
props{1} = ssObj.a;
props{2} = ssObj.b;
end
Lets test those classes:
x = ss(1,2);
xx = ess(3,x)
I get:
xx =
ess handle
Properties:
c: 3
a: 1
b: 2
Methods, Events, Superclasses

Recursively calling a class (Implementing linked list)

Hi I am trying to implement a linked list in Matlab.
The implementation I am hoping to do is (this is the C equivalent):
class Node{
public Node* child;
}
I have looked around but don't seem to get anything quite close.
I guess that you want to implement a linked list:
classdef Node < handle
properties
Next = Node.empty(0); %Better than [] because it has same type as Node.
Data;
end
methods
function this = Node(data)
if ~exist('data','var')
data = [];
end
this.Data = data;
end
end
end
Creation :
n1 = Node('Foo'); %Create one node
n2 = Node('Bar'); %Create another one
n1.Next = n2; %Link between them
Iteration:
n = n1;
while ~isempty(n)
disp(n.Data); %Change this line as you wish
n = n.Next;
end