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

Handle object as default class property value

April 8, 2015 18 Comments

We all know the benefits of setting default class-property values: it saves coding, increases class readability, improves maintainability and reduces the potential for coding bugs due to uninitialized properties. Basically, we’re setting default values of the class properties, so that whenever a new instance of this class is created, it will be recreated with these same default property values. This is the behavior in any self-respecting OOP language, and is a well-entrenched paradigm in OOP computing. Simple enough, right?
Well, unfortunately it doesn’t behave quite this way in Matlab…

Problem example

First, define class Internal as follows:

classdef Internal < hgsetget & matlab.mixin.Copyable
    properties
        Value = 0
    end
    methods
        function obj = Internal()
        end
        function set.Value(obj, newValue)
            obj.Value = newValue;
        end
        function str = char(obj)
            str = sprintf('Internal [Value=%s]', mat2str(obj.Value));
        end
        function disp(obj)
            disp(char(obj));
        end
    end
    methods (Static)
        function obj = getDefault()
            obj = Internal();
        end
    end
end

classdef Internal < hgsetget & matlab.mixin.Copyable properties Value = 0 end methods function obj = Internal() end function set.Value(obj, newValue) obj.Value = newValue; end function str = char(obj) str = sprintf('Internal [Value=%s]', mat2str(obj.Value)); end function disp(obj) disp(char(obj)); end end methods (Static) function obj = getDefault() obj = Internal(); end end end

Now define class External as follows:

classdef External < hgsetget & matlab.mixin.Copyable
    properties
        MyValue = Internal.getDefault;
    end
    methods
        function obj = External(varargin)
            % empty constructor
        end
        function set.MyValue(obj, newValue)
            obj.MyValue = newValue;
        end
        function str = char(obj)
            str = sprintf('External [MyValue = %s]', char(obj.MyValue));
        end
        function disp(obj)
            disp(char(obj));
        end
    end
end

classdef External < hgsetget & matlab.mixin.Copyable properties MyValue = Internal.getDefault; end methods function obj = External(varargin) % empty constructor end function set.MyValue(obj, newValue) obj.MyValue = newValue; end function str = char(obj) str = sprintf('External [MyValue = %s]', char(obj.MyValue)); end function disp(obj) disp(char(obj)); end end end

Now run the following (note the highlighted unexpected internal value):

>> clear classes
>> e1 = External
e1 =
External [MyValue = Internal [Value=0]]
>> e1.MyValue.Value = 1
e1 =
External [MyValue = Internal [Value=1]]
>> e2 = External   % This returns a bad value of 1 (should be 0!)
e2 =
External [MyValue = Internal [Value=1]]
>> e1 == e2   % this proves that e1~=e2 (as expected)
ans =     0
>> Internal.getDefault   % this proves that the default Internal value remains unchanged (as expected)
ans =
Internal [Value=0]

>> clear classes >> e1 = External e1 = External [MyValue = Internal [Value=0]] >> e1.MyValue.Value = 1 e1 = External [MyValue = Internal [Value=1]] >> e2 = External % This returns a bad value of 1 (should be 0!) e2 = External [MyValue = Internal [Value=1]] >> e1 == e2 % this proves that e1~=e2 (as expected) ans = 0 >> Internal.getDefault % this proves that the default Internal value remains unchanged (as expected) ans = Internal [Value=0]

Basically, this shows that setting e1.MyValue.Value=1 has also affected future class constructions, such that e2=External (which should have created a new handle object with a default property value of 0) now returns the modified value 1.

How is this possible?

The answer lies in the fine print of the documentation:
    Evaluation of property default values occurs only when the value is first needed, and only once when MATLAB first initializes the class. MATLAB does not reevaluate the expression each time you create a class instance.
In other words, when Matlab first loads the External class code into memory (typically upon its first instance creation), it assigns the handle reference to a new Internal instance to the class property. This same handle reference (memory pointer, in a broad sense) is used for all subsequent creations of External class instances. So basically, all instances of External share the same Internal object!
This does not affect properties that are initialized to primitive (non-object) data, nor to value classes (as opposed to handle classes). The reason is that Matlab’s built-in COW (copy-on-write) mechanism ensures that we get a new copy of a value class whenever one of its properties is modified. However, this does not happen in handle classes, so modifying Internal‘s property in one instance of External also affects the other instances.
So yes, it’s fully documented (sort of). But confusing? Counter-intuitive? Unexpected? – you bet!
In recent releases, Matlab increasingly relies on MCOS (Matlab’s latest OOP incarnation) for its internal codebase. I venture a guess that if a poll was made among MathWorker developers, the majority (if not vast majority) of them are not aware of this fine detail. Certainly programmers who come from other programming languages would not expect this behavior. This raises a concern that any internal Matlab object that has properties which are handle objects might incur hard-to-trace bugs due to this behavior.

Workaround and plea for action

At the moment, the only workaround is to programmatically set the property’s default value to a new instance of the handle class in the classes constructor. So, in our case, we would modify External‘s constructor as follows:

classdef External < hgsetget & matlab.mixin.Copyable
    properties
        MyValue  % no misleading default value here!    end
    methods
        function obj = External(varargin)
            % non-empty constructor
            obj.MyValue = Internal.getDefault;
        end...

classdef External < hgsetget & matlab.mixin.Copyable properties MyValue % no misleading default value here! end methods function obj = External(varargin) % non-empty constructor obj.MyValue = Internal.getDefault; end ...

I strongly urge MathWorks to modify this unexpected behavior (and certainly the documentation). I believe that the vast majority of MCOS users would welcome a change to the expected behavior, i.e., create a new Internal object at instance creation time rather than just at class-load time. Moreover, I bet that it would save many internal bugs in Matlab’s own code, which is probably by far the largest MCOS codebase worldwide…
I’m the first one to complain about backward incompatibilities, but in this particular case I think that it’s not an important concern since users should never rely on this “feature” in their code – it would be bad programming for so many reasons.
Reference: G1308623
Addendum April 11, 2015: Dave Foti (who heads MCOS development at MathWorks) and Sam Roberts (a former MathWorker) have provided important insight as to the reasons for this confusing behavior (read the comments below). Once we understand it, we can actually use it in interesting ways, to differentiate between class load-time defaults (in the properties section), and class-instantiation defaults (in the constructor). As noted below, MathWorks could probably do a better job of alerting users to the potentially confusion behavior, using either an MLint editor warning, and/or a run-time console warning (preferably both).

Related posts:

  1. Getting default HG property values – Matlab has documented how to modify default property values, but not how to get the full list of current defaults. This article explains how to do this. ...
  2. Class object creation performance – Performance aspects of Matlab class object creation are discussed, with specific suggestions. ...
  3. Setting class property types – take 2 – R2016a saw the addition of class property types. However, a better alternative has existed for many years. ...
  4. Setting class property types – Matlab's class properties have a simple and effective mechanism for setting their type....
  5. Class object tab completion & improper field names – Tab completions and property access can be customized for user-created Matlab classes. ...
  6. Performance: accessing handle properties – Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
MCOS Pure Matlab
Print Print
« Previous
Next »
18 Responses
  1. Jerome Lecoq April 8, 2015 at 13:49 Reply

    Wow, I wasn’t aware of this.

    I agree, this is terrible : a different behavior depending on if you initialize in the constructor or in the property list!

  2. Martin Lechner April 8, 2015 at 23:20 Reply

    We had the same problem last week. The only difference was, that we called the constructor directly, but the behaviour is the same.
    This problem is also very difficult to debug, because there is no convenient way as far I know to get the objects id in Matlab (like in Java with System.identityHashCode or ==), to see references to the same object. It would be perfect if it’s possible to show the reference address of handle objects in the Workspace viewer of Matlab.
    I’m also in favour to modify this behaviour in Matlab. For me it’s a bug and not a feature.

    • Dave Foti April 10, 2015 at 14:44 Reply

      While handle ID’s are not visible in MATLAB, == does compare two handle ID’s, provided the specific handle class hasn’t defined an override for the eq function. This can be used to ask if two handles refer to the same object.

  3. Sam Roberts April 9, 2015 at 04:43 Reply

    Hi Yair,

    You can reproduce this issue with a much simpler example:

    classdef MyTest1 < handle
        properties
            myValue = containers.Map
        end
    end

    classdef MyTest1 < handle properties myValue = containers.Map end end

    classdef MyTest2 < handle
        properties
            myValue
        end
        methods
            function obj = MyTest2
                obj.myValue = containers.Map;
            end
        end
    end

    classdef MyTest2 < handle properties myValue end methods function obj = MyTest2 obj.myValue = containers.Map; end end end

    >> a1 = MyTest1;
    >> a1.myValue('hello') = 1;
     
    >> b1 = MyTest1;
    >> b1.myValue('hello')
    ans =
         1
     
    >> a2 = MyTest2;
    >> a2.myValue('hello') = 1;
     
    >> b2 = MyTest2;
    >> b2.myValue('hello')
    Error using containers.Map/subsref
    The specified key is not present in this container.

    >> a1 = MyTest1; >> a1.myValue('hello') = 1; >> b1 = MyTest1; >> b1.myValue('hello') ans = 1 >> a2 = MyTest2; >> a2.myValue('hello') = 1; >> b2 = MyTest2; >> b2.myValue('hello') Error using containers.Map/subsref The specified key is not present in this container.

    I also have been bitten by this issue, and I agree that it can seem unexpected when you first come across it, especially if your previous experience is in other languages that don’t behave in this way. Nevertheless, this is the first time that I think I disagree with your conclusion.

    i) although it can be unexpected the first time you come across this behavior, it’s the sort of thing that doesn’t really bite you twice. Once you’re aware of it, you just know about it and it’s not really a problem. I can guarantee to you that any MathWorks developer who works in an OO style is aware of this behavior, so changing it is not going to save MathWorks from any significant number of bugs.

    ii) it is actually well-documented – just not on the page that you linked to. Go to that page and follow the link immediately underneath the piece you quoted, and you’ll come to a section “When MATLAB evaluates expressions” on the page “Expressions in Class Definitions”. The issue is really very thoroughly explained, with a couple of worked-through examples.

    iii) there are some sensible use cases for this feature (IMHO it is a feature), and some reasons why it’s a good design for MCOS. These are specifically related to the way MATLAB is typically used, that stand in contrast to other languages.

    For example, it is very common in MATLAB that one would rapidly implement different versions of a class, changing features all the time. Perhaps these might be statistical models, for example. At each stage you might want to create objects of the class, and serialize them to a .mat file. Later on, you might want to load in the old .mat files, after the class definition has changed. This is a very common workflow in MATLAB, because it’s not just a language – it’s an interactive environment for data analysis; but it would be very uncommon in a language such as Java or C. Implementing this sort of class-definition backward-compatibility is significantly easier if you take advantage of property defaults, instantiated at class-loading time. There’s an example of how and why you might want to do that on the doc page I mentioned above.

    By the way, this issue is part of a more general issue of the way MATLAB handles expressions in class definitions, and if you think this behavior is confusing, wait until you find out that you can also have expressions in property, method and class attributes. For example, it’s legal to say classdef (Sealed = logical(rand<0.5))) MyClass. Try doing that, then run clear classes and ?MyClass over and over πŸ™‚

    • Sam Roberts April 9, 2015 at 04:46 Reply

      Sorry, my less than and greater than symbols seem to have come through as HTML tags for some reason. Hopefully you’ll all be able to guess what I meant.

    • Yair Altman April 9, 2015 at 05:15 Reply

      Thanks for your detailed comment, Sam. I’m flattered that in 6 years this blog has been alive this is the first time you disagree with me, it says something coming from you πŸ™‚

      I still think that this so-called “feature” is confusing and should be changed, regardless of whether or not MathWorkers are aware of it (I’d still be willing to wager that most of them are not, but that’s a minor issue). You yourself have said it has bitten you in the past, and so was I, and so apparently were others. I’m betting that the number of people who were bitten by this (including numerous people who are not even aware that they were bitten, since it results in very hard-to-trace bugs!), far outnumbers the number of people who serialize classes to MAT file, and then load them in the same Matlab session. The ratio between these two populations is probably greater than 100:1, IMHO.

      This “feature” is no different than any other bug that has a workaround, and typically only bites you once since you’d know about it after that point. The case of needing to place a simple drawnow to avoid a Matlab hang when using standard dialog windows, is another example of something that is extremely difficult to trace and debug, and only bites you once since you’d automatically avoid the problem in the future. I think you’d agree that it cannot be considered a beneficial “feature”. Nor can this one I believe.

      At the very least, Matlab should issue a warning when loading such a class with an internal handle property, so that users could at least know about it and not waste endless hours chasing after illusive bugs.

    • Sam Roberts April 9, 2015 at 11:11 Reply

      Well – we’ll agree to disagree, I guess.

      Just another brief point, though: this is not just an issue with using a handle object as a default property, it’s an issue with evaluating any expression as a default property. For example, you can set a property to have default value of datestr(now), and all objects will by default be given the time that the class was first instantiated. The expression can potentially be as complex as you like. In such a case, evaluation of the expression at class-loading time can also be advantageous: for example, if you have a Constant property with such a complex expression as its default, there’s no point in evaluating it every time an object is created, so you can do it just once at class-loading time.

      I suspect you may regard that as another very small side-benefit that doesn’t justify confusing behaviour, though πŸ™‚

      • Yair Altman April 11, 2015 at 10:02

        Thanks Sam – this is indeed a correct and important clarification.

    • Arthur Goldsipe April 10, 2015 at 11:12 Reply

      I’ve been bitten by this behavior, too. I wanted each object to have a different handle object on a property, and default property values initially seemed like the easiest way to do that. But upon reflection, I don’t think the current behavior should change. In fact, I think Sam’s example (Hi, Sam!) using datestr(now) perfectly illustrates what’s going on and why the current behavior makes sense. The whole point of a default value is so that it’s the same default for all objects. This can be confusing when you’re talking about handle objects. In your example, it sounds like you want each External object that’s constructed to also construct a different Internal object. But if you think about it, doesn’t that sounds exactly like something that should happen in a constructor?

  4. sebastian April 10, 2015 at 00:13 Reply

    For what it’s worth: for “somewhat” experienced Python programmers this feature may be less surprising than to others.

    The same principle in Python applies to default function arguments (which don’t exist in matlab) and I’d guess that the python/matlab internal reason for it being this peculiar way might be identical: Namely that the class definition is parsed at the some time, creating the corresponding metaclass object and simply assigning the default property values on each newly created instance of the class – using the normal copy semantics of the corresponding type.

    
    

    This Stackoverflow question reveals other advantages and disadvantages and speculations about the reasons (if any) behind this decision.

  5. Dave Foti April 10, 2015 at 14:42 Reply

    While I understand the source of confusion, I think Sam and Sebastian have provided most of the rationale for why MATLAB works the way it does. The class definition is evaluated once while constructors are executable functions that execute every time an object is instantiated. This gives the programmer the flexibility to choose whether an expression is evaluated once per class (in the definition) or once per object (in the constructor). In addition to the referenced benefits of having expressions evaluated only once, the idea with the class definition is that it provides information that can be queried by tools and used to help document the class. For example, because the meta.property.DefaultValue is a value, you can compare this value to the current value of an object property and you can ask what value will I get if I create an object. If default values are expressions that need to be evaluated every time, it is difficult for tools to query or display default values without causing unwanted side effects and a tool can’t be sure what specific value a new instance will get by default.

    I agree that MATLAB could do a better job providing hints in the editor when assigning default values to handle objects or expressions that can return different values every time they are evaluated.

    • Yair Altman April 11, 2015 at 11:21 Reply

      @Dave – thanks for the insight. I was hoping you’d pitch in at some point, and I’m happy that you did. I’ve updated the post text with a corresponding addendum. I hope that you do add the MLint warning and preferably also the runtime console warning, so that users would no longer be confused. Once users are aware of the distinction between class load-time and instantiation-time defaults, I agree that this could well be put into good use.

  6. DNF April 17, 2015 at 07:19 Reply

    Might this not be handled by introducing a property attribute to determine the behaviour?

    properties (InitializeForEachInstance = true)

    properties (InitializeForEachInstance = true)

    or something along those lines? I am quite unhappy with the current behaviour, and for my particular use I find the workaround (initializing in the constructor) to be ugly.

    • Martin Lechner April 22, 2015 at 00:38 Reply

      That would be a very good solution for this issue. The default value for this property should be true because the described use cases where this Matlab behaviour is advantageous are only useful for some special tasks.

  7. Ed Yu April 21, 2015 at 09:32 Reply

    To me this seems like a syntax issue… The behavior seems to be equivalent to Java’s static class level properties instead of the regular object instance properties. I don’t think the behavior absolutely needs to be changed but the way the declaration syntax should reflect this distinction. A feature? Definitely. But it introduces ambiguity. I agree with Yair that it’s best to have it changed… At the very least, the syntax of a class level property (static?) should be different from an instance-level property initialized within the constructor. This will benefit programmers that come from OOP background; at the very least, Java programmers like myself.

  8. Kyle June 29, 2016 at 00:39 Reply

    Is anyone aware if this is still the behavior in the newest Matlab version, 2016b? We have a very large suite of classes that now need to be sifted through to verify we’re not using this construction methodology. I’d guess we probably aren’t otherwise we’d have seen an error by now, but who knows, because I don’t know why we wouldn’t. Default handle properties are certainly a typical use case and one would not expect said property to be the the same instance of in all calls.

    • Sam Roberts June 30, 2016 at 02:10 Reply

      Yes, R2016b has the same behaviour.

  9. Manzn January 16, 2021 at 22:33 Reply

    Thank you man! you saved me, when there was no more light πŸ˜€

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
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) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
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