How do I create a property in a class that is a direct handle to another class object

6 views (last 30 days)
Currently I have two classes, a class that contains a structured definition, and another class that is supposed to fit that definition. The myDefinition class loads the definition from a data file.
Here is the classdef and are some example properties from the definition class:
classdef myDefinition
properties(constant)
lengthMin = 8;
lenthMax = 64;
scaleDefault = [1 1];
end
properties( GetAccess = public, SetAccess = immutable )
type;
definitionFile;
map;
elements = {};
end
methods
function obj = myDefinition (thistype, filenameDefinition)
elementTable = readtable(filenameDefinition);
%Loops through elements here...
end
end
end
The function is really not important, but for an overview, the constructor for myDefinition reads the file in the path specified by the string or char array in filenameDefintion (which is a csv file), reads it in with readtable, and loops through the rows to create the elements.
I then have a class which has to follow one of the definitions in a myDefinition class.
classdef myDefinedObject
properties ( Access = private )
mindatabits = 0;
maxdatabits = 64;
end
properties ( SetAccess = immutable, GetAccess = public )
mydef;
type;
name;
a;
x;
end
methods
function obj = myDefinedObject( num, thisDefinition, data )
if isa(thisDefinition, 'myDefinition')
obj.mydef = thisDefinition;
else
obj.mydef = [];
warning('No valid definition file provided');
end
%Based on the number input, gets name and other properties from
%the definition, then parses the data based on the properties
%from the lookup in the definition
end
end
end
I have other methods in myDefinedObject other than the constructor, and the key point is that some of those methods need the definition that's stored in mydef. To determine what needs to be done. That is why I currently have mydef as an internal property of the myDefinedObject class.
In a typical run of my program, I have one or two objects of myDefinition (which can each be a very large object, memory wise) but could have dozens of objects of myDefinedObject. So, ideally, mydef would actually be a handle to a myDefinition object, rather than a copy of the object itself.
I know I can make a handle class
classdef myDefinitionHandle < handle
properties(setAccess = immutable)
def;
end
function obj = myDefinitionHandle(thisDefinition)
if isa(thisDefinition, 'myDefinition')
obj.def = thisDefinition;
else
obj.def = [];
warning('No valid definition file provided');
end
end
end
And then change myDefinedObject to check for a myDefinitionHandle and thus effectively have a handle to the definition.
However, the handle is now another layer away when trying to access it in my methods versus when I just stored the definition itself in every myDefinedObject object. For example, I have a method to check that a obj.a is correct based on the obj.type value and what is defined for that type in the definition:
function obj = comply(obj)
if strlength(obj.a) > obj.mydef.def.elements{obj.type}.max
obj.a = obj.a(1:obj.mydef.def.elements{obj.type}.max);
end
end
(Note: comply is a method that is called from set.a, and this is a very simplified example)
I would much prefer just to call obj.mydef.elements{obj.type}.max instead of obj.mydef.def.elements{obj.type}.max as the additional .def object layer in the class really serves no purpose.
Is there a better way I can structure these classes to make it so that mydef directly points to the thisDefinition object passed in the constructor?
  3 Comments
Chris
Chris on 17 Jan 2023
Edited: Chris on 17 Jan 2023
Does something like this work? I think you would have to set it like this in myDefinedObject, and the myDefinition object would have to exist (so, pass it to the constructor or setter). The handle is only set once--if something changes in the myDefinition object, the value obj.mydef.elements points to remains.
obj.mydef.elements = @() myDefinitionObj.elements
some background, in case you haven't seen it:
https://undocumentedmatlab.com/articles/handle-object-as-default-class-property-value

Sign in to comment.

Answers (2)

Captain Karnage
Captain Karnage on 23 Jan 2023
After contemplating this for a while, I came up with my own solution. I attempted a "universal" solution that will create a handle to an object of nearly any class.
In theory, the attached class could be used to clone any class and create a handle to it and all of its properties, with a few relatively minor limitations. It uses the metaproperties of the class it is copying to determine all of its properties and methods. If they are publically readable, it then creates its own properties (using dynamicprops) to those public properties and function_handles to thos public methods. It cannot, of course, copy any private properties or methods - but since it is a handle, those private properties and methods would be invoked whenever using a public property or method that is dependent upon them, anyway, so I can't think of any issues that will create off hand.
In practice, it has worked with all of my custom classes so far, but I haven't been able to do thorough testing of it to verify. If anyone else happens across this, would love feedback as to whether it works or not on other various classes.
  1 Comment
Captain Karnage
Captain Karnage on 31 Jan 2023
Found two issues in my Class:
1 - copying any class with a disp or display methods causes an error due to not being supported by MATLAB due to temporary nature of their output. I have a fix for that I'll upload later.
2 - the function handles are all 0 argument function handles - so yeah, they won't work with any functions that need an input argument. Haven't figured out how to work that one out yet.

Sign in to comment.


Chris
Chris on 18 Jan 2023
Edited: Chris on 18 Jan 2023
mydef = myDefinition;
a = myDefinedObject([],mydef,[]);
whos mydef a
Name Size Bytes Class Attributes a 1x1 80 myDefinedObject mydef 1x1 800 myDefinition
a.type
ans = function_handle with value:
@()thisDefinition.type
a.type()
ans = 10×10
92 99 1 8 15 67 74 51 58 40 98 80 7 14 16 73 55 57 64 41 4 81 88 20 22 54 56 63 70 47 85 87 19 21 3 60 62 69 71 28 86 93 25 2 9 61 68 75 52 34 17 24 76 83 90 42 49 26 33 65 23 5 82 89 91 48 30 32 39 66 79 6 13 95 97 29 31 38 45 72 10 12 94 96 78 35 37 44 46 53 11 18 100 77 84 36 43 50 27 59
  1 Comment
Captain Karnage
Captain Karnage on 20 Jan 2023
Interesting approach. I hadn't considiered that doing a function handle to a varible / object would function that way. My first thought was "is that another one of those undocumented features?" I saw your answer before your additional comment... later I looked back and saw your comment and followed the link, which confirmed that thought.
Before your reply was posted, I did a "brute force" solution of making a handle version of myDefinition which took in a "real" myDefinition object and copied its properties to the handle version. It did the job, but I wish I had seen this solution first. Though going through that made me wonder if I could make a universal "handle" type that could copy any other type of object, but a handle version by making use of the handle subclass of dynamicprops as a superclass.
At first, I was thinking using this solution I still would have to define function handles to every property I wanted to access as well (as you had with obj.type = @() thisDefinition.type; in myDefinedObject so that a.type would return the type from mydef as well. However, I see that I can reference the sub by doing a.mydef().type. Odd because it's really a property and it's being called as a function... but works.
I'm looking back at my question and realize I wasn't completely clear on one thing. If I'm in a myDefinedObject class variable, I'm fine having a layer to access the definition. So, a.mydef.type is fine. When I was making a separate handle class containing a myDefinition object inside, I would have had to do something like a.mydefhandle.mydef.type - that is what I wanted to avoid. And I did not want myDefinedObject class to be a handle in and of itself.

Sign in to comment.

Categories

Find more on Data Type Identification in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by