Update a value class property only if required
32 views (last 30 days)
Show older comments
Hello everyone,
I am new to object oriented programming and have some issues getting the behavior of my class in the way I want it. I have several input properties and a "dependent" output property. Because the algorithm to compute the output is numerically intensive, I do not want to handle it as an actual dependent property. It should only be updated if necessary. Also I want to be able to save my results to my hard drive, which would not work with a dependent property.
I got this basically working if my class is a handle class as shown in the example down below. But I do not like how handle classes function. In particular it can be very unintuitive to the user if they try something like this:
A = myclass(1,2);
B = A;
A.input1 = 5;
So here is my example with the handle class. Can anyone tell me if that can also be achieved with a value class? General improvement suggests are welcome as well :-)
Thanks a lot in advance!
classdef myclass < handle
properties
input1
input2
output
update_required
end
methods
function obj = myclass(value1, value2)
obj.input1 = value1;
obj.input2 = value2;
obj.output = [];
end
function set.input1(obj, value)
if obj.input1 == value
return
end
obj.input1 = value;
obj.update_required = true;
end
function set.input2(obj, value)
if obj.input2 == value
return
end
obj.input2 = value;
obj.update_required = true;
end
function value = get.output(obj)
if obj.update_required
disp('Update required.')
obj.output = obj.input1 + obj.input2;
obj.update_required = false;
else
disp('No update required.')
end
value = obj.output;
end
end
end
3 Comments
Peng Li
on 13 Apr 2020
and you are setting another property within your set.input1, set.input2 methods. This is not recommended, and thus shouldn't be done. It's better to use an event listener to accomplish what you want, and thus you'll need to do a handle class.
And another comment is that, to make your set. function work for a value class, you need to return the obj within the set. method. You don't need an out variable for handle class as what you are working on all refers to that instance. But for value class, you are working on copies and if you don't return the obj, you loose it. Matlab will complain this as well.
for value class
obj = set.input1(obj, val)
for handle class
set.input1(obj, val)
Peng Li
on 13 Apr 2020
within some modifications, you might be able to make it work with these all twisted set. methods, although it's not recommended.
Accepted Answer
Peng Li
on 14 Apr 2020
Edited: Peng Li
on 14 Apr 2020
I think my solution works if you reset your update_required within your if...end block.
classdef myclass
properties
input1
input2
end
properties (Dependent = true)
output
update_required
end
properties (Hidden = true)
output_
update_required_
end
methods
function obj = myclass(value1, value2)
obj.input1 = value1;
obj.input2 = value2;
obj.output = value1 + value2;
end
function obj = set.input1(obj, value)
if obj.input1 == value
obj.update_required = false;
return
end
obj.input1 = value;
obj.update_required = true;
end
function obj = set.input2(obj, value)
if obj.input2 == value
obj.update_required = false;
return
end
obj.input2 = value;
obj.update_required = true;
end
function value = get.output(obj)
if obj.update_required
disp('Update required.')
obj.output = obj.input1 + obj.input2;
obj.update_required = false;
else
disp('No update required.')
end
value = obj.output_;
end
function obj = set.output(obj, val)
obj.output_ = val;
end
function val = get.update_required(obj)
val = obj.update_required_;
end
function obj = set.update_required(obj, val)
obj.update_required_ = val;
end
end
end
>> A = myclass(1, 2);
>> A
A =
Update required.
myclass with properties:
input1: 1
input2: 2
output: 3
update_required: 1
>> A.input1 = 1
A =
No update required.
myclass with properties:
input1: 1
input2: 2
output: 3
update_required: 0
>> A.input2 = 2
A =
No update required.
myclass with properties:
input1: 1
input2: 2
output: 3
update_required: 0
>> A.input1 = 5
A =
Update required.
myclass with properties:
input1: 5
input2: 2
output: 7
update_required: 1
>> A.input2 = 10
A =
Update required.
myclass with properties:
input1: 5
input2: 10
output: 15
update_required: 1
4 Comments
Matt J
on 15 Apr 2020
This creates Code Analyzer warnings. You could probably make it work if input1 and input2 were made to be Dependent properties as well. I don't think it's worth it, though...
Peng Li
on 15 Apr 2020
yeah this is annoying and that's why i don't like this twisted way, although it seems to work. And i don't want to make input1 and input2 dependent, as conceptually I think they shouldn't be.
More Answers (2)
Matt J
on 13 Apr 2020
Edited: Matt J
on 13 Apr 2020
You have two separate issues that need to be addressed. The issue of handle class versus value class is the easier of the two. The only difference is that in a value class implementation, your set.prop() methods must return an output.
The second issue is whether input1 and input2 should be Dependent classes. They should, since it is dangerous for a non-Dependent property set or get method to reference other properties. This is true regardless of whether myclass is a value or handle class. Below is the value class implementation I would recommend.
classdef myclass
properties (Hidden)
Input1 %holds the data for "input1"
Input2 %holds the data for "input2"
output
end
properties
update_required;
end
properties (Dependent)
input1
input2
end
methods
function obj = myclass(value1, value2)
obj.Input1 = value1;
obj.Input2 = value2;
obj.output = [];
obj.update_required=1;
end
function input1=get.input1(obj)
input1=obj.Input1;
end
function input2=get.input2(obj)
input2=obj.Input2;
end
function obj=set.input1(obj, input1)
if obj.Input1 == input1
return
end
obj.Input1 = input1;
obj.update_required = true;
end
function obj=set.input2(obj, input2)
if obj.Input2 == input2
return
end
obj.Input2 = input2;
obj.update_required = true;
end
function value = get.output(obj)
if obj.update_required
disp('Update required.')
obj.output = obj.input1 + obj.input2;
obj.update_required = false;
else
disp('No update required.')
end
value = obj.output;
end
end
end
4 Comments
Matt J
on 14 Apr 2020
Edited: Matt J
on 14 Apr 2020
As I think about it, I don't believe you can do this as a value class if the update of "output" has to be postponed until the moment it is needed. You can force an update whenever input1 or input2 are changed (see my 2nd answer), but the update has to occur at that moment.
Matt J
on 14 Apr 2020
Edited: Matt J
on 14 Apr 2020
Is there a reason you don't update when changes to input1 or input2 occur, like in the following?
classdef myclass
properties
input1;
input2;
output;
end
methods
function obj = myclass(value1, value2)
obj.input1 = value1;
obj.input2 = value2;
end
function obj=set.input1(obj, input1)
if obj.input1 == input1
return
end
obj.input1 = input1;
obj = update_output(obj);
end
function obj=set.input2(obj, input2)
if obj.input2 == input2
return
end
obj.input2 = input2;
obj = update_output(obj);
end
function obj=update_output(obj)
obj.output=obj.input1+obj.input2;
end
end
end
2 Comments
Matt J
on 14 Apr 2020
Edited: Matt J
on 14 Apr 2020
So I guess I have to live with the fact that my class needs to be a handle class.
No, that's not the only solution. Instead of a get.output() method, you could instead use an ordinary method like below. This does not enable the syntax you were looking for, but it does allow you to use value classes and still get the computational efficiency you're after. I would also argue that it is probably better to undertake a large computation in an explicit function call like this, rather than have it hidden from view in a property access operation.
function obj=update_Object(obj)
if obj.update_required
disp('Update required.')
obj.output = obj.input1 + obj.input2;
obj.update_required = false;
else
disp('No update required.')
end
end
See Also
Categories
Find more on Software Development Tools in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!