Matlab objects have numerous built-in properties (some of them publicly-accessible/documented and others not, but that’s a different story). For various purposes, it is sometimes useful to attach custom user-defined properties to such objects. While there was never a fully-documented way to do this, most users simply attached such properties as fields in the UserData property or the object’s [hidden] ApplicationData property (accessible via the documented setappdata/getappdata functions).
An undocumented way to attach actual new user-defined properties to objects such as GUI handles or Java references has historically (in HG1, up to R2014a) been to use the undocumented schema.prop function, as I explained here. As I wrote in that post, in HG2 (R2014b onward), we can use the fully-documented addprop function to add new custom properties (and methods) to such objects. What is still NOT documented, as far as I could tell, is that all of Matlab’s builtin handle graphics objects indirectly inherit the
dynamicprops class, which allows this. The bottom line is that we can dynamically add custom properties in run-time to any HG object, without affecting any other object. In other words, the new properties will only be added to the handles that we specifically request, and not to any others.
All this is important, because for some unexplained reason that escapes my understanding, MathWorks chose to seal its classes, thus preventing users to extend them with sub-classes that contain the new properties. So much frustration could have been solved if MathWorks would simply remove the Sealed class meta-property from its classes. Then again, I’d have less to blog about in that case…
Anyway, why am I rehashing old news that I have already reported a few years ago?
Well, first, because my experience has been that this little tidbit is [still] fairly unknown by Matlab developers. Secondly, I happened to run into a perfect usage example a short while ago that called for this solution: a StackExchange user asked whether it is possible to tell a GUI figure’s age, in other words the elapsed time since the figure was created. The simple answer would be to use setappdata with the creation date whenever we create a figure. However, a “cleaner” approach seems to be to create new read-only properties for the figure’s CreationTime and Age:
First, create a small Matlab function as follows, that attaches the CreationTime property to a figure:
function setCreationTime(hFig,varargin) hProp = addprop(hFig,'CreationTime'); hFig.CreationTime = now; hProp.SetAccess = 'private'; % make property read-only after setting its initial value hProp = addprop(hFig,'Age'); hProp.GetMethod = @(h,e) etime(datevec(hFig.CreationTime), clock); % compute on-the-fly hProp.SetAccess = 'private'; % make property read-only end
Now assign this function as the default CreateFcn callback function for all new figures from now on:
That’s it – you’re done! Whenever a new figure will be created from now on, it will have two custom read-only properties: CreationTime and Age.
>> newFig = figure; >> newFig.CreationTime ans = 737096.613706748 >> ageInDays = now - newFig.CreationTime ageInDays = 0.0162507836846635 >> ageDuration = duration(ageInDays*24,0,0) ageDuration = duration 00:23:24 >> ageString = datestr(ageInDays, 'HH:MM:SS.FFF') ageString = '00:23:24.068' >> ageInSecs = newFig.Age ageInSecs = 1404.06771035492
Note that an alternative way to set the computed property Age would have been to set its value to be an anonymous function, but this would have necessitated invoking it with parenthesis (as in:
ageInSecs = newFig.Age()). By setting the property’s GetMethod meta-property we avoid this need.
Keen readers will have noticed that the mechanism that I outlined above for the Age property/method can also be used to add custom user methods. For example, we can create a new custom property named refresh that would be read-only and have a GetMethod which is the function handle of the function that refreshes the object in some way.
Do you have any special uses for custom user-defined properties/methods in your program? or perhaps you have a use-case that might show MathWorks why sub-classing the built-in classes might improve your work? if so, then please place a comment about it below. If enough users show MathWorks why this is important, then maybe it will be fixed in some future release.