Best way to forward object properties

24 views (last 30 days)
men8th
men8th on 31 Dec 2019
Commented: men8th on 12 Feb 2020
What is the best way to forward object properties when undertaking object oriented design with Matlab. Here I use forwarding in the sense of this Wikipedia article: Forwarding (object-oriented programming). I've asked a similar question to this before, but now I understand the terminology a bit better so I think it warrents a fresh attempt.
For example, I have a couple of objects as follows:
classdef parentObj
properties
parentProp % must stay synchronised with childThingy.childProp
childThingy childObj
end
end
classdef childObj
properties
childProp % must stay synchronised with parentProp
end
end
parentProp and childProp must always have the same value in order to maintain a consistent state.
My problem comes because there are a number of ways of achieving the forwarding and I find myself using them interchangeably and inconsistently. I'm searching for the one true way. For example, you can...
1) use an object derived from a handle class (eg a pointer) to forward properties from the parent to the child and ensure they stay synchronised
2) configure the parent object with "normal" (eg not dependent) properties and use the set method in the parent to update the corresponding properties in the child - the code analyser doesn't particularly like this and warns that the set method should not access another property to prevent problems due to initialisation order when loading saved objects
3) make the properties in the parent dependent, then use the set method to set the child properties and the get method to retrieve child properties and return them as the parent properties.
4) have a helper function in the parent, eg updateChildProperties(), which is called via the set method when the parent properties are changed.
5) use SetObservable on the parent object and add listeners on the child object. Works well apart from when the properties of the child object are dependent, and are not recalculated until accessed.
6) have a property on the child object called .parentObj. Make properties dependent on the child object, and retrieve values using the getters for the properties, reading them from .parentObj.
Any insights most gratefully received.
  6 Comments
Adam
Adam on 12 Feb 2020
Edited: Adam on 12 Feb 2020
I did create a class that acted as a kind of half-way house between a regular property and a dependent property, called a JustInTimeProperty to handle situations like this, although I always forget how to use my own class as obviously it can't behave as an actual property attribute like 'Dependent', it is a property itself.
In essence though, what it does is wrap up a private property with a paired dependent property and a 'calculation function'.
So the get function for the dependent property will check if the private property is empty. If it isn't empty it will just return it, if it is empty it will call the calculation function to calculate and set the private property.
I also pass in an object of another class I wrote, let's call it EventHub, whose role is simply to allow dependencies to be registered in the form of an object and events (or 'PostSet' property events). Whenever any of those registered events trigger this class fires off its own event (so basically it collects any number of disparate events and funnels them all into a single new event). The point of this is that the JustInTimeProperty listens for this one event and responds by setting the private stored property back to empty and firing off its own event. It also abstracts away those other dependencies into this EventHub rather than in the JustInTimeProperty itself, though they could also have been registered with it directly for the same effect I guess.
So, it is rather complicated (though I already had that second class for other purposes so was easier for me to design the JustInTimeProperty to use it rather than implement its own dependency handling), but it does its job - the idea being that if I have something that takes a long time to calculate I register its calculation function with this class, alongside an object of the EventHub class. I register any events that would cause the value to need to be recalculated in the EventHub, e.g. 'PostSet' events for parameter properties changing. Then if one of those events triggers, the JustInTimeProperty resets, fires off its event so that anything that was using it knows it has changed and can request it again if they want. Then when they make that request, because the private property is now empty it will trigger the calculation function again.
I chose not to go down the route of having the JustInTimeProperty automatically call the calculation function again on getting notification of a dependency changing because it may be it no longer needs to be recalculated so it is wasted - hence it sending an event so the function/class using it can decide if it wants to trigger the update.
It would be nice though if such a property type were embedded in the Matlab language as this isn't a trivial implementation, even though the two classes are only 90 and 58 lines, including lots of white space and method/property blocks! It works for what I wanted though.
men8th
men8th on 12 Feb 2020
That's an interesting insight Adam. I've developed a similar pattern for lazy evaluation of expensive properties but without the events. The way it works is as follows:
If an object has a property which expensive to evaluate and is calculated from the values of, say, 3 input properties, I define the expensive property as a normal property (not dependent) and I also define a private property, say pIsCalculationOutOfDate. Whenever one of the 3 input properties changes is use that propertie's setter to store the changed value and then set pIsCalculationOutOfDate = true. When triggered, the setter for the expensive property calls the function to calculate the property value and returns it, the setter then stores the value. The first line of the calculation function checks to see if pIsCalculationOutOfDate = true and returns early if not, thus preventing evaluation if nothing has changed. If other expensive properties are calculated at the same time, eg as intermediate steps, these can be recorded too. It looks a bit like this:
classdef LazyEvaluationDemo < handle
properties(GetAccess = public, SetAccess = private)
expensiveProperty
end
properties
input1
input2
input3
end
properties(Private = true)
pIsCalculationOutOfDate
end
methods
function set.input1(obj,value)
obj.input1 = value;
obj.pIsCalculationOutOfDate = true;
end
function set.input2(obj,value)
obj.input1 = value;
obj.pIsCalculationOutOfDate = true;
end
function set.input3(obj,value)
obj.input1 = value;
obj.pIsCalculationOutOfDate = true;
end
function value = get.expensiveProperty1(obj)
obj.doExpensiveComputation();
value = obj.expensiveProperty1;
end
function value = get.expensiveProperty2(obj)
obj.doExpensiveComputation();
value = obj.expensiveProperty2;
end
end
methods
function value = doExpensiveCalculatoin(obj)
if ~obj.pIsCalculationOutOfDate
return
else
obj.pIsCalculationOutOfDate = false;
end
input1 = obj.input1;
input2 = obj.input2;
input3 = obj.input3;
obj.expensiveProperty1 = input1+input2+input3;
obj.expensiveProperty2 = obj.expensiveProperty1 + input1*input2/input3;
end
end
end

Sign in to comment.

Answers (0)

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Products


Release

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!