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 (email)
  •  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
  • Josh (11 hours 18 minutes ago): Dear Yair, Small typo; you wrote >>Move lines up or down – CTRL + ALT + UP or DOWN allows you to move selected lines up or down but it’s actually ALT+SHIFT then UP/DOWN...
  • Yair Altman (7 days 5 hours ago): You can try to increase the Java heap memory size in the Matlab preferences (General => Java Heap Memory). Any changes to the settings will only take effect after restarting...
  • Thomas (7 days 7 hours ago): Hello, thanks for sharing! I currently receive the following memory error message when using savezip with a big object (Matlab R2020b, Windows 10). Error using...
  • Yair Altman (10 days 14 hours ago): Yerlan – either use menuItem1.setEnabled(0) or set(menuItem1,'Enabled',0)
  • Manzn (10 days 17 hours ago): Thank you man! you saved me, when there was no more light 😀
  • Yerlan (11 days 22 hours ago): Hello Mr. Altman, how can I disable menu items in the context menu? E.g. when I am trying to do this: menuItems = jmenu.getSubElements; menuItem1 = menuItems(1);...
  • Yair Altman (12 days 14 hours ago): Thanks for the note Eric – you forgot the crucial call to jTable.setLabelTable(labelTabl e) – I added it into your code snippet above.
  • Erik (14 days 1 hour ago): Thank you for this — I don’t know if this has been mentioned anywhere else before, but it could be useful to mention how to add custom labels to a jslider. I did the...
  • turhv (26 days 20 hours ago): very nice! work perfectly to me in MATLAB 2019a. thanks!!!
  • Jianfei (59 days 23 hours ago): I have tried the MathWorks CheckBoxList in Matlab 2015b. For whatever the reason, I can’t change the font properties. I can change the font color, but changing font properties...
  • Donato Coppola (65 days 19 hours ago): Hi Yair, I have a problem with the double format. When I run the treeTable function, the numbers in double format cells are displayed with comma as decimal separator. How can...
  • Kim (71 days 9 hours ago): Yair, the following didn’t work for me either: jh.setBorderPainted(false); Regards, Kim
  • Adil (73 days 10 hours ago): Thank you for the blog, it was useful for me. I have a file named App_project.mlapp.zip and when I extract it through Winzip it gives all the files exactly as you described above. I...
  • Mr Ashley Trowell (75 days 20 hours ago): Thank you so much for this analysis. Also, I find it somewhat horrifying. The take away seems to be to use && / || and NOT and / or. Thanks a bunch! ~Ashley
  • Matt (80 days 22 hours ago): Late reply I know, but you can call custom shortcuts with alt-#. Hold down Alt to see what number is assigned to the shortcuts you’ve created. Now if there was a way to create a...
Contact us
Undocumented Matlab © 2009 - Yair Altman
Scroll to top