I have an object apple created by my own class in MATLAB:
apple = classA();
The class looks like this:
classdef classA < handle
properties
color = 'red';
end
methods
function obj = classA()
% ...
end
end
end
The question: How do I get the object or handle pointer of apple? I want to search for objects by their properties, like:
isprop(eval(mat(i).name),'color')
with mat = whos. So I need to get the pointer of the object, represented by the struct mat(i).name. I just need the reference, not a copy of the desired object. The purpose is this:
If I get the pointer somehow, like
ptr_to_apple_object = get_pointer_fct( mat(i).name )
then I am able to change the properties of the apple-object like:
ptr_to_apple_object. color = 'yellow'
Do you have any ideas? Thanks.
There's really no good way to find all current objects of a particular class, but you could use whos to get a struct about all variables, loop through this and determine which ones have the property you and then modify
variables = whos;
for k = 1:numel(variables)
obj = eval(variables(k).name);
if isobject(obj) && isprop(obj, 'color')
obj.color = 'yellow';
end
end
If you're looking for a specific class, you can use the class field of the output of whos
is_class = ismember({variables.class}, 'classA');
instances = variables(is_class);
for k = 1:numel(instances)
obj = eval(instances(k).name);
obj.color = 'yellow';
end
Update
Since you are subclassing handle, when you assign your instance to a new variable (obj = val(variables(k).name) above), it does not create a copy of your instance, but rather a new reference to the same object.
b = classA;
c = b;
b.color = 'red';
c.color
% 'red'
Related
I created an object in MATLAB by using my own class my_class like this
car = my_class();
with
classdef my_class < handle
properties
color = 'red';
end
methods
function obj = my_class()
% ...
end
end
end
Now I am trying to find my object by its class (my_class) or by properties (color). But findall or findobj always return an empty matrix, whatever I am doing. Do you have any clue? Thanks.
EDIT I need something like this:
car1 = my_classA();
car2 = my_classA();
house1 = my_classB(); ... house25 = my_classB();
tree1 = my_classC(); ... tree250 = my_classC();
In my code, I can not refer to the names of the handles (like car2.color), because I have many different objects and I want to search for them by a function, that looks like the following one:
loop over all objects (maybe with findobj/findall without knowing object name/handle)
if object is of class `my_classA`
get handle of `my_classA`
change `color`
else if object is of class `my_classB`
get handle of `my_classB`
do something ...
end
end
I think you just want this:
% Create example array of objects
A(20) = object;
[A([3 14 17]).color] = deal('blue');
% Get those objects which are red, and change to orange
[A(strcmp({A.color}, 'red')).color] = deal('orange');
I have to admit, findobj would have been much better to read. But that only works on graphics handles as far as I'm aware, so you'd have to overload it for your class.
And that overloaded function, would contain something similar to this.
EDIT as noted by Navan, this works:
B = findobj(A, 'color', 'red');
[B.color] = deal('orange');
seems to be faster than the strcmp method, too.
In Matlab, I can define a class as such:
classdef klass < handle
properties(Dependent)
prop
end
end
Matlab is perfectly happy instantiating an object of this class, even without defining a getter for prop. It only fails when I try to access it (understandably). I'd like to set the GetMethod dynamically based upon the property's name.
Unfortunately, even when the property is Dependent, the meta.property field for GetMethod is still read-only. And while inheriting from dynamicprops could allow adding a property and programmatically setting its GetMethod in every instance, I don't believe it could be used to change an existing property. I may have to go this route, but as prop must exist for every object I'd prefer to simply set the getter on a class-by-class basis. Is such a thing possible?
An alternative solution could be through some sort of catch-all method. In other languages, this could be accomplished through a Ruby-like method_missing or a PHP-like __get(). But as far as I know there's no (documented or otherwise) analog in Matlab.
(My use case: this class gets inherited by many user-defined subclasses, and all their dependent properties are accessed in a similar way, only changing based on the property name. Instead of asking users to write get.* methods wrapping a call to the common code for each and every one of their dependent properties, I'd like to set them all dynamically with anonymous function pointers containing the necessary metadata).
Here is my proposal: create a method in the superclass called add_dyn_prop. This method is to be called in the subclasses instead of creating a dependent property the usual way.
The idea is that the superclass inherit from dynamicprops and use addprop to add a new property, and set its accessor methods manually based on its name.
classdef klass < dynamicprops
methods (Access = protected)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
% NOTE: this has to be a simple function_handle (#fun), not
% an anonymous function (#()..) to avoid infinite recursion
p.GetMethod = #get_method;
p.SetMethod = #set_method;
% nested getter/setter functions with closure
function set_method(obj, val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
now in the subclass, instead of defining a dependent property the usual way, we use this new inherited function in the constructor to define a dynamic property:
classdef subklass < klass
%properties (Dependent, SetAccess = private)
% name
%end
%methods
% function val = get.name(obj)
% val = 'Amro';
% end
%end
methods
function obj = subklass()
% call superclass constructor
obj = obj#klass();
% define new properties
add_dyn_prop(obj, 'name', 'Amro');
add_dyn_prop(obj, 'age', [], false)
end
end
end
The output:
>> o = subklass
o =
subklass with properties:
age: []
name: 'Amro'
>> o.age = 10
o =
subklass with properties:
age: 10
name: 'Amro'
>> o.name = 'xxx'
You cannot set the read-only property 'name' of subklass.
Of course now you can customize the getter method based on the property name as you initially intended.
EDIT:
Based on the comments, please find below a slight variation of the same technique discussed above.
The idea is to require the subclass to create a property (defined as abstract in the superclass) containing the names of the desired dynamic properties to be created. The constructor of the superclass would then create the specified dynamic properties, setting their accessor methods to generic functions (which could customize their behavior based on the property name as you requested). I am reusing the same add_dyn_prop function I mentioned before.
In the subclass, we are simply required to implement the inherited abstract dynamic_props property, initialized with a list of names (or {} if you dont want to create any dynamic property). For example we write:
classdef subklass < klass
properties (Access = protected)
dynamic_props = {'name', 'age'}
end
methods
function obj = subklass()
obj = obj#klass();
end
end
end
The superclass is similar to what we had before before, only now is it its responsibility to call the add_dyn_prop in its constructor for each of the property names:
classdef klass < dynamicprops % ConstructOnLoad
properties (Abstract, Access = protected)
dynamic_props
end
methods
function obj = klass()
assert(iscellstr(obj.dynamic_props), ...
'"dynamic_props" must be a cell array of strings.');
for i=1:numel(obj.dynamic_props)
obj.add_dyn_prop(obj.dynamic_props{i}, [], false);
end
end
end
methods (Access = private)
function add_dyn_prop(obj, prop, init_val, isReadOnly)
% input arguments
narginchk(2,4);
if nargin < 3, init_val = []; end
if nargin < 4, isReadOnly = true; end
% create dynamic property
p = addprop(obj, prop);
%p.Transient = true;
% set initial value if present
obj.(prop) = init_val;
% define property accessor methods
p.GetMethod = #get_method;
p.SetMethod = #set_method;
% nested getter/setter functions with closure
function set_method(obj,val)
if isReadOnly
ME = MException('MATLAB:class:SetProhibited', sprintf(...
'You cannot set the read-only property ''%s'' of %s', ...
prop, class(obj)));
throwAsCaller(ME);
end
obj.(prop) = val;
end
function val = get_method(obj)
val = obj.(prop);
end
end
end
end
Note: I did not use ConstructOnLoad class attribute or Transient property attribute, as I am still not sure how they would affect loading the object from a saved MAT-file in regards to dynamic properties.
>> o = subklass
o =
subklass with properties:
age: []
name: []
>> o.name = 'Amro'; o.age = 99
o =
subklass with properties:
age: 99
name: 'Amro'
Check if this is what you want. The problem is that the user will need to get the properties using (), which may be quite boring, but anyway, I think this way you can change the variables. You can't change them directly on the class, but you can change the objects property values on demand. It doesn't need to change the values on the constructor, you can do that using another function that will be inherited by the classes.
klass1.m
classdef(InferiorClasses = {?klass2}) klass < handle
methods
function self = klass
selfMeta = metaclass(self);
names = {selfMeta.PropertyList.Name};
for name = names
switch name{1}
case 'prop_child_1'
self.(name{1}) = #newGetChild1PropFcn;
case 'prop_child_2'
self.(name{1}) = #newGetChild2PropFcn;
end
end
end
end
methods(Static)
function out = prop
out = #defaultGetPropFcn;
end
end
end
function out = defaultGetPropFcn
out = 'defaultGetPropFcn';
end
function out = newGetChild1PropFcn
out = 'newGetChild1PropFcn';
end
function out = newGetChild2PropFcn
out = 'newGetChild2PropFcn';
end
klass2.m
classdef klass2 < klass
properties
prop_child_1 = #defaultGetChildPropFcn1
prop_child_2 = #defaultGetChildPropFcn2
end
methods
function self = klass2
self = self#klass;
end
end
end
function out = defaultGetChildPropFcn1
out = 'defaultGetChildPropFcn1';
end
function out = defaultGetChildPropFcn2
out = 'defaultGetChildPropFcn2';
end
Output:
a = klass2
b=a.prop_child_1()
b =
newGetChild1PropFcn
Just started crash coursing in Matlab OO programing and I would like to write a set method for a object that will set the value then reciprocate by setting itself in the relevant field on the other object.
classdef Person
properties
age;
sex;
priority; % net priority based on all adjustment values
adjustment; % personal adjustment value for each interest
family;
end
methods
function obj = set.sex(obj, value)
if value == 'm' || value == 'f'
obj.sex = value;
else
error('Sex must be m or f')
end
end
function obj = set.family(obj,value)
if class(value) == 'Family'
obj.family = value;
else
error('Family must be of type Family')
end
end
end
end
classdef Family
properties
husband;
wife;
children;
elders;
adjustment; % interest adjustment values
end
methods
function this = set.husband(this,person)
if class(person) == 'Person'
this.husband = person;
person.family = this;
else
error('Husband must be of type Person')
end
end
function this = set.wife(this,person)
if class(person) == 'Person'
this.wife = person;
person.family = this;
else
error('Wife must be of type Person')
end
end
end
end
So what I have to do now is:
p = Person
f = Family
f.husband = p
p.family = f
What I would like is for family and person to auto set themselves in each other:
p = Person
f = Family
f.husband = p
And Family set.husband function will set p's family value to f. Why is my code not working? As far as I can tell I'm doing what is suggested in the comments.
Edit:
After some messing around I've confirmed that "this" and "person" are objects of the correct type. Ultimately the issue is that Matlab passes by value rather then by reference. Unless anyone knows a way around that I'll answer myself when I can.
Normal objects are usually considered value objects. When they are passed to a function or a method, only the value is passed not a reference to the original object. Matlab may use a read-only referencing mechanism to speed things up, but the function or method cannot change the properties of the original object.
To be able to pass an input parameter by reference, your custom object needs to be a handle object. Simply when defining your class, inherit from handle and that should do the trick:
classdef Person < handle
and
classdef Family < handle
If I have a class defined as
classdef myclass
properties
foo = 3;
bar = 7;
end
end
And I want to access property foo I would write
obj = myclass()
obj.foo % Gives me 3
But, if I only have a string representation of the property name, and don't know which property it is how would I do it then? As in the example below:
obj.someFunction('foo') % or
someFunction(obj, 'foo') % should both give me the value of obj.foo
What I want to do is have a list of properties, iterate through it and get the value for a specific object.
It seems like it should be possible, but I failed to find it in the documentation.
value = getfield(struct, 'field')
You can use:
obj = myclass();
propName = 'foo';
propValue = obj.(propName);
For more information, see Generating Field Names from Variables and Dot-Parentheses.
cellfun( #(prop) obj.(prop), properties(obj), 'UniformOutput', false )
I am creating a class in MATLAB and while I have little experience with objects, I am almost positive I should be able to set a class property using a class method. Is this possible in MATLAB?
classdef foo
properties
changeMe
end
methods
function go()
(THIS OBJECT).changeMe = 1;
end
end
end
f = foo;
f.go;
t.changeMe;
ans = 1
Yes, this is possible. Note that if you create a value object, the method has to return the object in order to change a property (since value objects are passed by value). If you create a handle object (classdef foo<handle), the object is passed by reference.
classdef foo
properties
changeMe = 0;
end
methods
function self = go(self)
self.changeMe = 1;
end
end
end
As mentioned above, the call of a setting method on a value object returns the changed object. If you want to change an object, you have to copy the output back to the object.
f = foo;
f.changeMe
ans =
0
f = f.go;
f.changeMe
ans =
1