Main Content

Avoid Property Initialization Order Dependency

Control Property Loading

Problems can occur if property values depend on the order in which load sets the property values.

Suppose that your class design is such that both of the following are true:

  • A property set method changes another property value.

  • A property value is computed from other property values.

Then the final state of an object after changing a series of property values can depend on the order in which you set the properties. This order dependency can affect the result of loading an object.

The load function sets property values in a particular order. This order can be different from the order in which you set the properties in the saved object. As a result, the loaded object can have different property values than the object had when it was saved.

Restore Nondependent Properties

If a property set function changes the values of other properties, then define the Dependent attribute of that property as true. MATLAB® does not save or restore dependent property values.

Use nondependent properties for storing the values set by the dependent property. Then the load function restores the nondependent properties with the same values that were saved. The load function does not call the dependent property set method because there is no value in the saved file for that property.

Dependent Property with Private Storage

The Odometer class avoids order dependences when loading objects by controlling which properties are restored when loading:

  • The Units property is dependent. Its property set method sets the TotalDistance property. Therefore load does not call the Units property set method.

  • The load function restores TotalDistance to whatever value it had when you saved the object.

classdef Odometer
   properties(Constant)
      ConversionFactor = 1.6
   end
   properties
      TotalDistance = 0
   end
   properties(Dependent)
      Units
   end
   properties(Access=private)
      PrivateUnits = 'mi'
   end
   methods
      function unit = get.Units(obj)
         unit = obj.PrivateUnits;
      end
      function obj = set.Units(obj,newUnits)
         % validate newUnits to be a char vector
         switch(newUnits)
            case 'mi'
               if strcmp(obj.PrivateUnits,'km')
                  obj.TotalDistance = obj.TotalDistance / ...
                     obj.ConversionFactor;
                  obj.PrivateUnits = newUnits;
               end
            case 'km'
               if strcmp(obj.PrivateUnits,'mi')
                  obj.TotalDistance = obj.TotalDistance * ...
                     obj.ConversionFactor;
                  obj.PrivateUnits = newUnits;
               end
            otherwise
               error('Odometer:InvalidUnits', ...
                  'Units ''%s'' is not supported.', newUnits);
         end
      end
   end
end

Suppose that you create an instance of Odometer and set the following property values:

odObj = Odometer;
odObj.Units = 'km';
odObj.TotalDistance = 16;

When you save the object:

  • ConversionFactor is not saved because it is a Constant property.

  • TotalDistance is saved.

  • Units is not saved because it is a Dependent property.

  • PrivateUnits is saved and provides the storage for the current value of Units.

When you load the object:

  • ConversionFactor is obtained from the class definition.

  • TotalDistance is loaded.

  • Units is not loaded, so its set method is not called.

  • PrivateUnits is loaded from the saved object.

If the Units property was not Dependent, loading it calls its set method and causes the TotalDistance property to be set again.

Property Value Computed from Other Properties

The Odometer2 class TripDistance property depends only on the values of two other properties, TotalDistance and TripMarker.

The class avoids order dependence when initializing property values during the load process by making the TripDistance property dependent. MATLAB does not save or load a value for the TripDistance property, but does save and load values for the two properties used to calculate TripDistance in its property get method.

classdef Odometer2
   properties
      TotalDistance = 0
      TripMarker = 0
   end
   properties(Dependent)
      TripDistance
   end
   methods
      function distance = get.TripDistance(obj)
         distance = obj.TotalDistance - obj.TripMarker;
      end
   end
end

Related Topics