MATLAB Answers

0

[Warning] Why is it bad practice to set additional class properties when using a set method (prompting a warning)?

Asked by D. Plotnick on 25 Mar 2019
Latest activity Commented on by Guillaume
on 29 Mar 2019
I have a class with several properties, and I want it so that if I set one of those properties, it effectively resets additional properties. Now, these are not fully dependent properties, since I want to be able to manipulate them as well. Here is a MWE
classdef testClass
properties
A(2,1) double = [5;1];
B(1,1) double
end
methods
function obj = set.A(obj,val)
obj.A = val;
obj.B = sum(obj.A); % This is where the warning pops in
end
function obj = doThing(obj)
obj.B = 2*obj.B;
end
end
end
The warning reads "The set method for propery 'A' should not access another property ('B')". The more detailed warning talks about dependency issues and ordering. Now, again, B is not a dependent or transient property.
I know I can do various things to make sure that there are no errors because of this: 'B' initializes as 0 because I have defined it in the properties block, and I can get the "proper" starting value by including something like this in the constructor:
function obj = testClass
obj.B = sum(obj.A);
end
So, my question is whether this is still bad coding practice despite taking care that properties are appropriately set? Is there another, better way of resetting certain semi-dependent properties when another property is modified.
Cheers,
-DP

  0 Comments

Sign in to comment.

2 Answers

Answer by Steven Lord
on 28 Mar 2019
 Accepted Answer

Be very careful not to get yourself into a recursive situation like the class I posted earlier this month for this Answer does.
I would probably make B a Dependent property with a get.B method that accesses the A property. See this documentation page for some information about dependent properties.
A couple observations about your class:
  1. Your default value for the A property does not satisfy the size validation you've listed in your file. Either the default value should be [5; 1] or you should require A to be of size [1 2].
  2. Your doThing method doesn't make sense to me. As written it would make B out of sync with A. You could have doThing update A then the value of the Dependent property B would also be doubled. [I would not define a set.B method, or if I did I would implement it so it throws a user-friendly error message.]
function obj = doThing(obj)
obj.A = 2*obj.A;
end

  2 Comments

Fixed (1).
(2) Part of the point is to let B get out of sync with A, but that A always determines a starting point.
An analogy: B as a sandbox that I can play in, while A is the playground where the sandbox is installed. Each time I directly change A (swap playgrounds), I have to start with a fresh sandbox, whose starting properties are determined by the the property values of A. Once it is re-initialized, I can start mucking about with B again.
Thanks for the recursion example, I have been pretty concerned about that exact issue of cross-linking multiple properties.
In that case, you can just silence the mlint warning.
However, personally, I'd make A a private property and provide an explicit changePlayground method instead. It makes the intent clearer to the user.
classdef testClass
properties (Access = private)
A(2,1) double = [5;1];
end
properties
B(1,1) double
end
methods
function obj = changePlayground(obj, val)
obj.A = val;
obj.B = sum(obj.A);
end
function obj = doThing(obj)
obj.B = 2*obj.B;
end
end
end

Sign in to comment.


Answer by TADA
on 28 Mar 2019
Edited by TADA
on 28 Mar 2019

The thing is that dependent properties always invoked their get/set methods every time you access them. what you did doesn't necessarily create bugs. But to be on the safe side and get rid of the warning you can make A a dependent property and have it save its value in a private property, let's call it A_:
classdef testClass
properties (GetAccess=private,SetAccess=private)
A_(2,1) double = [5,1];
end
properties
B(1,1) double;
end
properties (Dependent)
A;
end
methods
function obj = set.A(obj,val)
obj.A_ = val;
obj.B = sum(obj.A);
end
function a = get.A(object)
a = object.A_;
end
function obj = doThing(obj)
obj.B = 2*obj.B;
end
end
end

  0 Comments

Sign in to comment.