Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Accessing private object properties

December 18, 2013 2 Comments

Some time ago, I needed to modify a property value of a class object. The problem was that this property was declared as private and for some reason my client could not modify the originating classdef to make this property accessible.

Problem definition

We start with a very simple class definition:

Inaccessible private property (or is it?)
Inaccessible private property (or is it?)

classdef MyClass
    properties (SetAccess=private)  %GetAccess = public
        y
    end
    properties (Access=private)  %GetAccess = SetAccess = private
        x
    end
    methods
        function obj = MyClass(x,y)  % constructor
            if nargin>0, obj.x = x; end
            if nargin>1, obj.y = y; end
        end
        function result = isPropEqualTo(obj,propName,value)
            result = (obj.(propName)==value);
        end
    end
end

classdef MyClass properties (SetAccess=private) %GetAccess = public y end properties (Access=private) %GetAccess = SetAccess = private x end methods function obj = MyClass(x,y) % constructor if nargin>0, obj.x = x; end if nargin>1, obj.y = y; end end function result = isPropEqualTo(obj,propName,value) result = (obj.(propName)==value); end end end

The problem is simple: we need to both get and set the value of inaccessible private properties x,y. But following object construction, MyClass enables direct read access only to property y, and write access to neither of its properties:

>> obj = MyClass(3,4)
obj =
  MyClass with properties:
    y: 4
>> obj.x
You cannot get the 'x' property of MyClass.
>> obj.x=5
You cannot set the 'x' property of MyClass.
>> obj.y=5
You cannot set the read-only property 'y' of MyClass.

>> obj = MyClass(3,4) obj = MyClass with properties: y: 4 >> obj.x You cannot get the 'x' property of MyClass. >> obj.x=5 You cannot set the 'x' property of MyClass. >> obj.y=5 You cannot set the read-only property 'y' of MyClass.

A dead end, would you say? – Well, it never stopped us before, has it? After all, is it not the raison-d’être of this blog?

Reading private properties

Getting the value of x is simple enough when we recall that calling Matlab’s struct function on a class object reveals all its hidden treasures. I wrote about this a couple of years ago, and I’m not sure how many people realize the power of this undocumented feature:

>> s = struct(obj)
Warning: Calling STRUCT on an object prevents the object from hiding its implementation details and should thus be avoided.
Use DISP or DISPLAY to see the visible public details of an object. See 'help struct' for more information.
(Type "warning off MATLAB:structOnObject" to suppress this warning.)
s =
    y: 4
    x: 3

>> s = struct(obj) Warning: Calling STRUCT on an object prevents the object from hiding its implementation details and should thus be avoided. Use DISP or DISPLAY to see the visible public details of an object. See 'help struct' for more information. (Type "warning off MATLAB:structOnObject" to suppress this warning.) s = y: 4 x: 3

As the warning mentions, we should not do this often (bad, bad boy!). If we must (I promise I had a good reason, ma!), then we can simply turn off the nagging warning:

warning off MATLAB:structOnObject

warning off MATLAB:structOnObject

We can now read all the private internal properties of the object. Yummy!

Setting private properties

The natural attempt would now be to update the struct’s fields with new values. Unfortunately, this does not affect the original class properties, since our struct is merely a copy of the original. Even if our original object is a handle class, the struct would still be a shallow copy and not a real reference to the object data.
Mex’s standard mxGetProperty cannot be used on the original object, because mxGetProperty returns a copy of the property (not the original reference – probably to prevent exactly what I’m describing here…), and in any case it can’t access private properties. mxSetProperty is a dead-end for similar reasons.
The core idea behind the solution is Matlab’s Copy-on-Write mechanism (COW). This basically means that when our struct is created, the field values actually hold references (pointers) to the original object properties. It is only when trying to modify the struct fields that COW kicks in and a real copy is made. This is done automatically and we do not have any control over it. However, we can use this information to our advantage by retrieving the field references (pointers) before COW has a chance to ruin them. Once we have the reference to the private data, we can modify the data in-place using a bit of Mex.
So the trick is to get the reference address (pointer) of s.x and s.y. How do we do that?
We can use another trick here, which is a corollary to the COW mechanism: when we pass s.x into a function, it is not a data copy that is being passed (by value), but rather its pointer (by reference). So we can simply get this pointer in our Mex function and use it to modify the original property value. Easy enough, right?
Not so fast. Don’t forget that s.x is merely a reference copy of the original property data. If we modify s.x‘s reference we’re just killing the so-called cross-link of the shared-array. What we need to do (more or less) is to traverse this cross-link back to its source, to get the real reference to the data.
Sounds complicated? Well, it is a bit. Luckily, Mex guru James (Jim) Tursa comes to the rescue with his mxGetPropertyPtr function on the File Exchange, which does all that for us. Once we have it compiled (the utility automatically Mex-compiles itself on first use), we can use it as follows (note the highlighted line using mxGetPropertyPtr):

/* Place in mxMySetProperty.c and mex-compile*/
#include "mex.h"
#include "mxGetPropertyPtr.c"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    mxArray *x;
    register double *xpr;
    int buflen;
    char *propName = "x";
    double newValue = -3.14159265358979;
    if ( nrhs > 1 ) {
        /* Get the specified property name (or "x" if not specified) */
        buflen = mxGetNumberOfElements(prhs[1]) + 1;
        propName = mxCalloc(buflen, sizeof(char));
        mxGetString(prhs[1], propName, buflen);
    }
    /* Get the pointer to the original property data */
    x = mxGetPropertyPtr(prhs[0],0,propName);
    if ( !x ) {
        mexErrMsgTxt("Failed to get pointer to property.");    }
    /* Display the existing property value */
    xpr = mxGetPr(x);
    mexPrintf("existing value of property %s = %f\n", propName, *xpr);
    /* Update the property with the new value */
    if ( nrhs > 2 ) {
        /* Get the specified new value (or -pi if not specified) */
        double *pr = mxGetPr(prhs[2]);
        newValue = *pr;
    }
    mexPrintf("setting value of property %s to %f\n", propName, newValue);
    *xpr = newValue;
}

/* Place in mxMySetProperty.c and mex-compile*/ #include "mex.h" #include "mxGetPropertyPtr.c" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { mxArray *x; register double *xpr; int buflen; char *propName = "x"; double newValue = -3.14159265358979; if ( nrhs > 1 ) { /* Get the specified property name (or "x" if not specified) */ buflen = mxGetNumberOfElements(prhs[1]) + 1; propName = mxCalloc(buflen, sizeof(char)); mxGetString(prhs[1], propName, buflen); } /* Get the pointer to the original property data */ x = mxGetPropertyPtr(prhs[0],0,propName); if ( !x ) { mexErrMsgTxt("Failed to get pointer to property."); } /* Display the existing property value */ xpr = mxGetPr(x); mexPrintf("existing value of property %s = %f\n", propName, *xpr); /* Update the property with the new value */ if ( nrhs > 2 ) { /* Get the specified new value (or -pi if not specified) */ double *pr = mxGetPr(prhs[2]); newValue = *pr; } mexPrintf("setting value of property %s to %f\n", propName, newValue); *xpr = newValue; }

Naturally, this simplistic Mex function should also be made to accept non-scalar values. This is left as an exercise to the reader.
The usage in Matlab of this mxMySetProperty function is super simple:

% Update obj.x from 3 => pi/2
>> mxMySetProperty(s,'x',pi/2);
existing value of property x = 3.000000
setting value of property x to 1.570796
% Update obj.y from 4 => -5
>> mxMySetProperty(s,'y',-5);  % here we can also use obj instead of s since obj.y is accessible
existing value of property y = 4.000000
setting value of property y to -5.000000
% Check that the struct copy has been updated correctly
>> s
s =
    y: -5
    x: 1.5707963267949
% Check that the original object's private properties have been updated correctly
>> obj
obj =
  MyClass with properties:
    y: -5
>> obj.isPropEqualTo('x',pi/2)
ans =
    1     % ==true

% Update obj.x from 3 => pi/2 >> mxMySetProperty(s,'x',pi/2); existing value of property x = 3.000000 setting value of property x to 1.570796 % Update obj.y from 4 => -5 >> mxMySetProperty(s,'y',-5); % here we can also use obj instead of s since obj.y is accessible existing value of property y = 4.000000 setting value of property y to -5.000000 % Check that the struct copy has been updated correctly >> s s = y: -5 x: 1.5707963267949 % Check that the original object's private properties have been updated correctly >> obj obj = MyClass with properties: y: -5 >> obj.isPropEqualTo('x',pi/2) ans = 1 % ==true

Jim Tursa has promised to supply a mxSetPropertyPtr variant of his mxGetPropertyPtr for the past two years (1,2,3,4). It will surely be more robust than my simplistic mxMySetProperty function, so I look forward to finally seeing it on FEX!

Conclusion

With some dirty tricks and undocumented hacks, we can both get and set private-access object properties. Please don’t do this unless you have a really good reason (such as a customer breathing down your neck, who doesn’t give a fig that his properties were declared private…).
The mechanism shown above can also be used to improve performance when updating public object properties, since it updates the data in-place rather than create a copy. This could be significant when the property size is very large (multi-MB), since it avoids unnecessary memory allocation and deallocation. You might think that with public properties we could use the standard mxGetProperty for this, but as I said above this function apparently returns a copy of the data, not a direct reference. Also note that last month I discussed additional performance aspects of accessing object properties.
This blog will now take a short break for the holidays. I hope you had a good ride this year, see you again on the other side of 2013.
Merry Christmas and happy New-Year everybody!

Related posts:

  1. Performance: accessing handle properties – Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  2. getundoc – get undocumented object properties – getundoc is a very simple utility that displays the hidden (undocumented) properties of a specified handle object....
  3. Adding dynamic properties to graphic handles – It is easy and very useful to attach dynamic properties to Matlab graphics objects in run-time. ...
  4. Handle object as default class property value – MCOS property initialization has a documented but unexpected behavior that could cause many bugs in user code. ...
  5. Accessing hidden HG2 plot functionality – In HG2, some of the plot functionality is hidden in undocumented properties. ...
  6. General-use object copy – Matlab's dual internal serialization/deserialization functions can be used to create duplicates of any object. ...
MCOS Mex Performance Undocumented feature
Print Print
« Previous
Next »
2 Responses
  1. Mauricio December 20, 2013 at 09:23 Reply

    Just an small additional comment on “Reading private properties”. If for whatever reason you do not want s = struct(obj) to reveal the structure, you can define inside the methods block the method “struct”

    methods
        function s = struct(obj)
            % ... do nothing...., or show error or...
        end
    end

    methods function s = struct(obj) % ... do nothing...., or show error or... end end

    Then s = struct(obj) will show nothing (or an error, or…) . But there is a solution for this too: s = builtin('struct',obj).

    Best regards

  2. Serializing/deserializing Matlab data | Undocumented Matlab March 10, 2014 at 06:22 Reply

    […] mxCreateUninitDoubleMatrix, mxCreateUninitNumericArray, mxCreateUninitNumericMatrix and mxGetPropertyShared. Unfortunately, mxSerialize and mxDeserialize remain among the functions that were left out, which […]

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
ActiveX (6) AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
  • Nicholas (3 days 19 hours ago): Hi Yair, Thanks for the reply. I am on Windows 10. I also forgot to mention that this all works wonderfully out of the editor. It only fails once compiled. So, yes, I have tried a...
  • Nicholas (3 days 19 hours ago): Hi Yair, Thanks for the reply. I am on Windows 10. I also forgot to mention that this all works wonderfully out of the editor. It only fails once compiled. So, yes, I have tried a...
  • Yair Altman (4 days 3 hours ago): Nicholas – yes, I used it in a compiled Windows app using R2022b (no update). You didn’t specify the Matlab code location that threw the error so I can’t help...
  • Nicholas (4 days 23 hours ago): Hi Yair, Have you attempted your displayWebPage utility (or the LightweightHelpPanel in general) within a compiled application? It appears to fail in apps derived from both R2022b...
  • João Neves (8 days 4 hours ago): I am on matlab 2021a, this still works: url = struct(struct(struct(struct(hF ig).Controller).PlatformHost). CEF).URL; but the html document is empty. Is there still a way to do...
  • Yair Altman (11 days 2 hours ago): Perhaps the class() function could assist you. Or maybe just wrap different access methods in a try-catch so that if one method fails you could access the data using another...
  • Jeroen Boschma (11 days 5 hours ago): Never mind, the new UI components have an HTML panel available. Works for me…
  • Alexandre (11 days 6 hours ago): Hi, Is there a way to test if data dictionnatry entry are signal, simulink parameters, variables … I need to access their value, but the access method depends on the data...
  • Nicholas (11 days 20 hours ago): In case anyone is looking for more info on the toolbar: I ran into some problems creating a toolbar with the lightweight panel. Previously, the Browser Panel had an addToolbar...
  • Jeroen Boschma (15 days 3 hours ago): I do not seem to get the scrollbars (horizontal…) working in Matlab 2020b. Snippets of init-code (all based on Yair’s snippets on this site) handles.text_explorer...
  • Yair Altman (43 days 5 hours ago): m_map is a mapping tool, not even created by MathWorks and not part of the basic Matlab system. I have no idea why you think that the customizations to the builtin bar function...
  • chengji chen (43 days 12 hours ago): Hi, I have tried the method, but it didn’t work. I plot figure by m_map toolbox, the xticklabel will add to the yticklabel at the left-down corner, so I want to move down...
  • Yair Altman (51 days 5 hours ago): @Alexander – this is correct. Matlab stopped including sqlite4java in R2021b (it was still included in 21a). You can download the open-source sqlite4java project from...
  • Alexander Eder (57 days 0 hours ago): Unfortunately Matlab stopped shipping sqlite4java starting with R2021(b?)
  • K (63 days 11 hours ago): Is there a way to programmatically manage which figure gets placed where? Let’s say I have 5 figures docked, and I split it into 2 x 1, I want to place 3 specific figures on the...
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top