MATLAB Answers

0

OOP Dynamic Properties ordering is very strange...

Asked by Ellis King on 18 Jun 2011
Latest activity Answered by William Warriner on 5 Aug 2019
I have a class defintion which makes use of OOP dynamicprops and I've noticed some odd behaivor in accessing the properties.
classdef myClass < dynamicprops
properties
x
end
methods
function this = myClass(x)
this.x = x;
end
end
end
If I add new properties to the class in a script which looks something like this
clear all
clear classes
hObj = myClass(10);
hObj.addprop('a');
hObj.addprop('b');
hObj.addprop('c');
hObj.addprop('d');
hObj.addprop('e');
fn = fieldnames(hObj)'
I was expecting the properties to be added to hObj in the same order that they are scripted in, but I find that the properties added to hObj do not get added in any consistent way. EVERY TIME I run the script, hObj is returned with a different order in the properties ?! Can anyone explain why these dynamic properties behave in such a stranage way? Is there no way to control the order in which these properties appear in the object?
It would be nice if I could control the order so that a function call like fieldnames(hObj) would return values in a predictable way. As a secondary but also irksome issue there appears to be no way to REMOVE a dynamic property once it has been added?!
... here is the output from 5 runs of the script I show above in R2010b:
fn =
'x' 'b' 'a' 'c' 'd' 'e'
fn =
'x' 'd' 'e' 'a' 'c' 'b'
fn =
'x' 'd' 'a' 'b' 'e' 'c'
fn =
'x' 'b' 'd' 'a' 'c' 'e'
fn =
'x' 'b' 'a' 'd' 'c' 'e'

  0 Comments

Sign in to comment.

4 Answers

Answer by Ellis King on 11 Aug 2011
 Accepted Answer

I did come up with a workaround for this which solves the immediate issue. It involves much more sophistication than I was originally hoping for with these classes, but it appears to do the trick. For the application I am working on, it would be counter-intuitive to have the dynamic properties appear to the user in an order that did not match the order they were inserted in. In general the property names are not inserted in alphabetical order. So here is an outline of the solution:
  • add a private, hidden property "dynPropOrder" for the class.
  • restrict access to addprop() by making it private for the class.
  • add a public addDynamicProperty(propertyName) method for the class, which inserts adds the dynamic property using addprop(), but also appends the property name to the hidden dynPropOrder property in a cell string array.
  • overload the display(), properties() and fieldnames() methods to return the properties in the expected order using the hidden dynPropOrder attribute.
  • add a removeDynamicProperty(propertyName) which does reverse operations for the specified property.
Does this seem overly complicated to anyone else? Like I said it works, but I am disappointed there did not appear to be a more straightforward way. I welcome any suggestions...

  0 Comments

Sign in to comment.


Answer by Daniel Shub
on 18 Jun 2011

Why not just overload fieldnames to return sort(fieldnames)?

  1 Comment

Daniel, I did essentially something like this for the classes I've been working with. It was a bit more complicated than what you describe because the first property 'x' should not have been included in the list of dynamic properties, and in general the dynamic property names are not inserted alphabetical order. (At the time of writing this I was primarily interested in getting the properties to appear in the order the dynamic properties were inserted). Creating a new display() method with some of the logic I describe above does do the trick. However what I was really hoping for is someone to comment on WHY the dynamic properties behave in such a non-deterministic way... ?

Sign in to comment.


Answer by Andrew Newell
on 18 Jun 2011

According to the documentation, you could add a property using a command like
Pa = hObj.addprop('a');
and later delete the property using
delete(Pa);
As for the order of names - even easier than overloading fieldnames would be to sort afterwards:
fn = sort(properties(hObj))'

  2 Comments

Andrew, you are correct about using that method to delete the dynamic properties -- I had missed that in the documentation. See my comment to Daniel above about using the sort() function.
Incidentally, if you forgot to save the handle Pa, it is still possible to delete the property 'a' using
delete(hObj.findprop('a'));

Sign in to comment.


Answer by William Warriner on 5 Aug 2019

I know this is a tremendously old question, but thought I would add that in (at latest) R2018b one can do the following, and it seems to work. Hopefully this helps future solution seekers like myself.
Add public overrides for properties and fieldnames like below. Technically properties() isn't a method of handle dynamicprops, but this should still work because methods are called before built-ins (https://www.mathworks.com/help/matlab/matlab_prog/function-precedence-order.html).
function value = properties( obj )
if nargout == 0
disp( builtin( "properties", obj ) );
else
value = sort( builtin( "properties", obj ) );
end
end
function value = fieldnames( obj )
value = sort( builtin( "fieldnames", obj ) );
end
Add a matlab.mixin.CustomDisplay superclass and add protected override like below.
function group = getPropertyGroups( obj )
props = properties( obj );
group = matlab.mixin.util.PropertyGroup( props );
end
The CustomDisplay mixin then displays only the group returned by getPropertyGroups() when disp() and display() are called. Since the properties() function called in getPropertyGroups() is the new "override", the group is displayed in sorted order.
Hope this helps someone!

  0 Comments

Sign in to comment.