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

12 visualizaciones (últimos 30 días)
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

Respuesta aceptada

Steven Lord
Steven Lord el 28 de Mzo. de 2019
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 comentarios
D. Plotnick
D. Plotnick el 28 de Mzo. de 2019
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.
Guillaume
Guillaume el 29 de Mzo. de 2019
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

Iniciar sesión para comentar.

Más respuestas (1)

TADA
TADA el 28 de Mzo. de 2019
Editada: TADA el 28 de Mzo. de 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

Categorías

Más información sobre Numerical Integration and Differential Equations en Help Center y File Exchange.

Community Treasure Hunt

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

Start Hunting!

Translated by