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 theTotalDistance
property. Thereforeload
does not call theUnits
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 aConstant
property.TotalDistance
is saved.Units
is not saved because it is aDependent
property.PrivateUnits
is saved and provides the storage for the current value ofUnits
.
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