OOP: How to avoid recalculation on dependent properties (I hope a MathWork Developer could give me an answer too)
5 views (last 30 days)
Show older comments
Dear MATLAB Community,
I am studying for the first time OOP on Matlab and have a question regarding how dependent properties can be calculated without falling on internal recalculations over and over again. For instance, consider the following class definition (taken from the MATLAB documentation):
classdef TensileData
properties
Material='';
SampleNumber=0;
Stress
Strain
end
properties (Dependent=true, SetAccess=private)
Modulus
end
methods
function obj=TensileData(material, samplenum, stress, strain)
if nargin>0
obj.Material=material;
obj.SampleNumber=samplenum;
obj.Stress=stress;
obj.Strain=strain;
end
end
function obj=set.Material(obj,material)
if ~(strcmpi(material,'aluminum') || ...
strcmpi(material,'stainless steel') || ...
strcmpi(material,'carbon steel'))
error('Material must be aluminum, stainless steel, or carbon steel')
end
obj.Material=material;
end
function modulus=get.Modulus(obj)
fprintf('!!!!! Running get.Modulus method...\n\n')
ind=find(obj.Strain>0);
modulus=mean(obj.Stress(ind)./obj.Strain(ind));
end
function disp(obj)
fprintf(1,'Material: %s\nSample Number: %g\nModulus: %1.5g\n',...
obj.Material, obj.SampleNumber, obj.Modulus);
end
function plot(obj,varargin)
plot(obj.Strain, obj.Stress, varargin{:})
title(['Stress/Strain plot for Sample',...
num2str(obj.SampleNumber)])
ylabel('Stress (psi)')
xlabel('Strain %')
end
end
end
... and at the command window, we type:
>> td=TensileData('carbon steel',001,[2e4 4e4 6e4 8e4],[.12 .20 .31 .40]);
>> td.Modulus
!!!!! Running get.Modulus method...
ans =
1.9005e+05
>> td.Modulus
!!!!! Running get.Modulus method...
ans =
1.9005e+05
As you can see, when I executed for the second time td.Modulus, MATLAB calculated the modulus value once more. My question is: if properties did not change, why does MATLAB need to calculate again the modulus value? Of course, this is not good programming practice (suppose td.Modulus is a time consuming method) and I was wondering whether we can avoid recalculation in this particular example. If so, how?
Your help will be greatly appreciated.
Thank you!
0 Comments
Accepted Answer
Honglei Chen
on 12 Nov 2012
Hi Ricardo,
By definition, the value of dependent property depends on the values of object's other properties and probably the internal state of the object too. Therefore, every time you try to get the property, it needs to be recalculated. I think for your problem, the best solution is to define an extra private property, say pModulus, which is set internally whenever necessary. Then in your get.Modulus method, you simply write
function modulus = get.Modulus(obj)
modulus = obj.pModulus;
end
This way, it only needs to be recalculated when necessary and still preserve the behavior of a dependent property.
HTH
6 Comments
Honglei Chen
on 13 Nov 2012
This is because when the method is invoked, you don't have value for parameters, such as stress yet. For your case, there are two solutions. Either set some default values for propeties, or set default values in the constructor and then at the end of constructor, call the method too to update the value.
HTH
More Answers (1)
Ricardo Prada
on 13 Nov 2012
Edited: Ricardo Prada
on 14 Nov 2012
3 Comments
Nate H
on 30 Mar 2015
Note: I'm sorry for bumping such an old thread. I'm just getting into OOP and came across this thread. I decided to check out the original poster's class.
First, with regard to your comment that running the method t.surflight calls your get.Data function 3 times. Yes, it will call your get.Data function 3 times because you have 3 calls within this line (of the surflight method):
surfc(obj.Data.X,obj.Data.Y,obj.Data.Matrix,...
Once for obj.Data.X, once for obj.Data.Y, and once for obj.Data.Matrix. It would probably be better for Matlab to recognize that it only needs to get the obj.Data structure once, but I can definitely understand how that may be difficult to code on their end. There is a much simpler way for you to fix your code:
function surflight(obj)
obj.FigHandle=figure;
datatmp=obj.Data;
surfc(datatmp.X,datatmp.Y,datatmp.Matrix,...
'FaceColor',[.8 .8 0], 'EdgeColor',[0 .2 0],...
'FaceLighting','phong');
camlight('left'); material('shiny'); grid('off');
colormap('copper');
end
By making a temporary data variable, datatmp, and assigning it to obj.Data you will only get 1 call to the get.Data method. Then you can use that temporary variable all you want within the surflight method.
Second, with regard to your comment that Mathworks should change how dependent properties work so that they only change when independent properties change; I think that maybe it would be nice for that to be an option, but I wouldn't want all dependent properties to act that way. Having dependent properties which calculate on call is useful for certain circumstances, just as having dependent properties which only update when certain (or all) independent properties change is useful. Honglei Chen's solution above should allow you to implement the functionality you want.
Finally, with regard to your final comment on why use dependent properties at all. Yes, the code you proposed there is completely sufficient, you can cut out the dependent property entirely. Now, consider that the data that you're plotting has units associated with them, lets say length. Before you plot something you might not be sure if you want it to show up in mm, m, or km. You can store the data raw like you have above in one unit system, then use a dependent property to store the scaled data. I find this to be very useful for my work for two reasons:
- I live in the USA, but work in SI units. This means I occasionally convert plots to US Customary units =( .
- Occasionally I will be analyzing oscilloscope data. The data comes in raw, and I may need to apply offsets scale factors. By using dependent properties I can keep a copy of unscaled data, choose my scale factors, and when I plot it it comes out correctly.
Now I'm sure there are other ways to do what I just described but hopefully you can understand that this is at least a legitimate use for the way dependent properties work. Finally, I completely understand your confusion around why something works the way it does. I wrote some code recently where I was trying to learn to use Events. The first one or two Events I created made total sense (and worked well), but third and fourth Events I realized could be implemented cleaner by using plain old methods. I think the lesson is that there are always multiple ways (paradigms) to code.
See Also
Categories
Find more on Matrix Indexing in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!