Retrieve the list of dynamic properties added to class in MATLAB OOP - matlab

With MATLAB it is possible to add dynamic properties to a class instance like this:
% Define a class supporting for dynamic properties
classdef DynamicClass < dynamicprops
end
% Add a dynamic property named 'toto' to some instance
c = DynamicClass();
c.addprop('toto');
Anyhow I did not find a way to later obtain the list of dynamic properties through reflection, indeed:
m = metaclass(c);
returns an empty list for properties:
PropertyList: [0x1 meta.property]
Even listing properties in dynamicprops superclass returns an empty list:
m.SuperClassList(1).PropertyList ==> 0x1 property array
Is there a way to obtain (through reflection) the list of dynamic properties added to a class ?
NB: Some workaround would be to maintain manual list newprop(end+1) = c.addprop(...) but it's not very practical to pass to another base class (where til now I was working with reflection to obtain information about properties in the child class).

Dynamic properties are not properties of the class, they're properties only of the object - note that if DynamicClass inherits from dynamicprops, then different objects of class DynamicClass can have a different set of properties:
>> a = DynamicClass;
>> b = DynamicClass;
>> a.addprop('hello');
>> a
a =
DynamicClass with properties:
hello: []
>> b
b =
DynamicClass with no properties.
For this reason, you're not going to be able to get any information about them via reflection, which is by definition getting information about the class.
You've given a solution (use properties to retrieve a list the names of all properties of the object, dynamic or not, then use findprop to get the property itself, and then get information about the property).
This is likely to work OK in most cases, but note that properties only returns a list of the properties that are both Hidden = false and GetAccess = public (and that's true even if you call properties inside a method of the object). By default, properties added via addprop meet both of those criteria, but it's possible to change their attributes after adding them, and they won't show up with your solution. The same goes if you call fieldnames on the object.
Another thing that might work for you would be to use isprop to directly check whether the object has a property of interest. This works even if the property is Hidden, or GetAccess = private. Usefully, isprop works on arrays of objects, so you can create an array of objects of class DynamicClass, then apply isprop to get an array of logicals.
But the only way I know of reliably getting everything (private or not, hidden or not, and whether you know the names of the properties beforehand or not) is to just dump the object into a struct temporarily, then get the fieldnames, as #Marek suggests.

cs = struct(c)
if it's only for listing and accessing the names of the properties, this should be sufficient
fieldnames( cs)

I found a workaround to retrieve meta information even for dynamic properties. I'm using properties to obtain the list of properties (this includes dynamic ones) and findprop to retrieve information through reflection in base class:
function [] = baseClassRoutine(obj)
propNames = properties(obj);
propCount = length(propNames);
for idx = 1:propCount,
propName = propNames{ki};
propMeta = obj.findprop(propName);
... So now can inspect meta about all properties (including dynamic ones) ...
end
end

Related

How can I modify the read-only outputs of an Autoencoder object?

I get an object of class type Autoencoder after running the specified function:
[X,T] = wine_dataset;
hiddenSize = 25;
autoenc1 = trainAutoencoder(X,hiddenSize,...
'L2WeightRegularization',0,...
'SparsityRegularization',0,...
'SparsityProportion',1,...
'DecoderTransferFunction','purelin');
If I try to query one of the properties, I can get it without problem,
>> autoenc1.EncoderWeights(1,1)
ans = -0.0404
However, if I try to set it, I get an error:
>> autoenc1.EncoderWeights(1,1) = 0.4
In class 'Autoencoder', no set method is defined for Dependent property 'EncoderWeights'. A
Dependent property needs a set method to assign its value.
Why are you getting this problem?
To understand this behaviour we should take a look inside the Autoencoder class (\MATLAB\R20###\toolbox\nnet\nnet\nnnetwork\Autoencoder.m). We can see the following:
'EncoderWeights' is defined inside a properties(SetAccess = private, Dependent) block.
A public "getter" method is defined for this property: function val = get.EncoderWeights(this).
Thus, we see that 'EncoderWeights' is neither a publicly settable field, nor is there a public setter method for it - so it's not surprising you're getting an error. BTW, on R2018b the error might be a bit more informative:
You cannot set the read-only property 'EncoderWeights' of Autoencoder.
(If you are unfamiliar with the concepts I used above, I suggest you read about classes in MATLAB.)
How to solve it?
You can use the network() method of you Autoencoder object to get a network object, then customize it as you please. In your case you would assign the new weight(s) into net.IW{1}. Afterwards you can train, sim etc.

Get object handle given the name as a string (MATLAB)

Being given the name of a variable as a string (in my case the name of an existing Simulink.Parameter variable in the workspace selected by the user as a design variable for optimization), I would like to be able to access the properties of the object such as Simulink.Parameter.Min, Simulink.Parameter.Max, Simulink.Parameter.Value without using eval(). So far I am employing the (very ugly) solution
varnames = {'var1','var2'}; % Simulink.Parameter objects existing in workspace
objects = cell(length(varnames),1);
for i = 1:length(varnames)
eval(['objects{i}=', varnames{i}, ';']) % Store objects in a cell array
end
Ideally, this would look like:
objects = get_object_handles_from_string(varnames);
value_1 = object{1}.Value(:);
Otherwise a method returning the variable name given the object handle would also be acceptable.
Methods that I found not to be working but might be useful otherwise:
whos finds variable names and properties in the current workspace but no handles.
inputname returns the variable name of an explicit function input as a string but does not work for cell arrays of objects (see this question).
str2func returns a function handle with a string as input but does not enable access to attributes.
findobj returns objects given an array of objects to iterate over which I do not have. Might there be a method returning all workspace variable handles as an array?
Thanks!
This is exactly what eval is for. Yes, you should avoid using eval, but if you want to have a user type in stuff to be evaluated, you need eval. Or evalin if you want to evaluate it in the base or caller workspace rather than the current workspace.
There are no such thing as "object handles" (except graphics objects, but that is not what you are talking about here). There are variables owning arrays of data, that is it.
If you don't trust your users, don't use eval. They could type in anything, including clear all or !\rm -rf /* (or whatever the Windows equivalent is to erase the disk).
In this case, and presuming there is a limited set of variables that the user can specify, do
var1 = 1;
var2 = 2;
varnames = {'var1','var2'}; % Simulink.Parameter objects existing in workspace
objects = cell(size(varnames));
for i = 1:numel(varnames)
objects{i} = get_variable_value(varnames{i}) % Store objects in a cell array
end
function val = get_variable_value(name)
switch name
case 'var1'
val = evalin('caller',var1);
case 'var2'
val = evalin('caller',var2);
otherwise
error('Illegal variable name')
end

How Realm handles dynamic dispatch with List<T> and RealmOptional<T>?

Realm relies on dynamic dispatch to access ObjectiveC runtime for some KVC mechanisms. Model properties should be marked with dynamic keyword to enable KVC that is used by Realm objects to fill them with exact values. So you can have model defined like this:
class Car: Object {
dynamic var color = ""
dynamic var age = 0
}
At some level you would be able to set properties like this:
var car = Car()
car["color"] = "white"
car["age"] = 20
This works for all basic types like Int or String but doesn't work with generic classes and structures since they can't be represented in Objective C. Realm uses two of those types:
List<T>
RealmOptional<T>
When adding properties of these types to the Realm models, you add them without dynamic keyword:
let cars = List<Car>
let registration = RealmOptional<String>
What mechanism Realm uses to set and read data of those types without using dynamic dispatch?
Update 1
Upon some inspection, I've found that Realm uses some Objective C runtime methods like class_copyPropertyList() and property_getName() for introspection of property names. What I haven't found yet is how properties are populated with correct data when you read from Realm? Is that part of the ObjectStore C++ framework?
Generic properties such like List<T> or RealmOptional<T> cannot be appeared from Objective-C. Realm uses Swift's reflection (Mirror()) to inspect those.
(See https://github.com/realm/realm-cocoa/blob/b71daecd0f4cf7a89fcb30178be02f506d9b3124/RealmSwift/Object.swift#L310-L316)
Then directly access their ivar: https://github.com/realm/realm-cocoa/blob/76d1018b32ba98babce31afbefd31863075cde8c/Realm/RLMObjectSchema.mm#L217-L223
These generic properties are dispatched statically. Realm cannot hook accessing those. That's why those properties must be declared as let. Realm cannot see re-assign the properties.

Import class to access constant values

I defined a class in one of my many MATLAB packages. To my suprise, I could not access a constant property of my class without importing the class definition. Even if it is a method of the class itself. Like so:
classdef TestClass
properties( Constant )
c=0;
end
methods
function obj = TestClass()
end
function getC(obj)
import test.TestClass;
disp(TestClass.c);
end
end
end
I just want to check whether I am doing something wrong here or is this the correct way to use constants in MATLAB.
Since you have placed TestClass inside a package Matlab needs to know where to look to find the definition for this class, even if it's a reference from within the class or function. An alternate to the above code could be:
function getC(obj)
disp(test.TestClass.c);
end
Alternately, if within a class, constant values can be accessed from the object itself.
function getC(obj)
disp(obj.c);
end
If neither of these is working for you, you may need to refresh the classdef for TestClass from memory. This will cause matlab to reload the constant value, which is pulled into Matlab when it first parses the classdef file to determine the structure of the class. This can be done using clear classes, however a warning that it will also clear all other classes, variables, and any breakpoints you have set.
If you want to see if this is necessary you can view the metaclass object to determine what Matlab "thinks" your class structure should be. You can do this using the following.
mc = ?test.TestClass;
mc.PropertyList
You may need to index into the property list to find the specific property you are interested in, but the thing you are looking for are the following fields.
Name: 'c'
Constant: 1
DefaultValue: 0

Add elements to matlab cell array member variable

i have a class called sampleClass with a cell array member variable called list.
Now i am trying to add elements to the internal list. For this purpose, i created the method addToList. The method simply tries to add elements to the list.
classdef sampleClass
properties
list = {}
end
methods
function addToList(obj)
obj.list{end+1}='test';
obj.list
end
end
end
Now the problem is, that the elements are not stored in the list.
Inside the function addToList the following output signalizes that the element is stored in the list:
>> samp = sampleClass();
>> samp.addToList
ans =
'test'
But after leaving the function, the element is no longer accessible:
>> samp.list
ans =
{}
Has anybody an idea what's going wrong? I am using Matlab 7.11.0 (R2010b).
Thanks for your help.
Julien
That's because you forgot to inherit from the handle class:
classdef sampleClass < handle %// Change here!
properties
list = {}
end
methods
function addToList(obj)
obj.list{end+1}='test';
obj.list
end
end
end
If you want to retain the changes made when modifying an instance of your class, you must inherit from the handle class. This can be done by taking your class definition (first line of your code), and doing < handle. If you don't, then any changes you make will not be saved. To show that this works, this is what I get in MATLAB:
>> samp = sampleClass();
>> samp.addToList
ans =
'test'
>> samp.list
ans =
'test'
To be more verbose, here's what the MATLAB docs say about handle:
The handle class is the superclass for all classes that follow handle semantics. A handle is a reference to an object. If you copy an object's handle, MATLABĀ® copies only the handle and both the original and copy refer to the same object data. If a function modifies a handle object passed as an input argument, the modification affects the original input object.
As such, you need to inherit from the handle class so that you have a reference back to the object you created. Any changes you make to the instance of your class will be remembered if you inherit from handle. If you don't, no changes you make get registered.