Here is the example:
if(value != ageValue) {
ageValue = value;
}
I mean, if we assign the value of a variable to another one, why would we need to check if they have anyway the same value?
That confuses me. Here is the broader context:
private double ageValue;
public double Age {
get {
return ageValue;
}
set {
if(value != ageValue) {
ageValue = value;
}
}
}
Yes, this if is useless. You check if the value are the same (and set it if not).
When the !=-operator is not overloaded, then is this:
private double ageValue;
public double Age
{
get { return ageValue; }
set
{
if (value != ageValue)
{
ageValue = value;
}
}
}
same to
private double ageValue;
public double Age
{
get { return ageValue; }
set { ageValue = value; }
}
The if is, on inspection, not redundant. It depends on the remaining implementation. Note that in C#, != can be overloaded, which means that evaluation can have side effects. Futhermore, the checked variables could be implemented as properties, which also can have side effects on evaluation.
In a winforms control we had set the BackgroundColor to a specific color:
myControl.BackgroundColor = Color.White
Under specific circumstances this could happen in a tight loop and lead to a frozen UI. After some performance analysis we found that this call was the reason for the frozen UI and so we simply changed it to:
if (myControl.BackgroundColor != Color.White)
myControl.BackgroundColor = Color.White
And the performance of our tool was back on track (and then we eliminated the reason of the tight loop).
So this check is not always redundant. Especially if the target is a property which does more within the setter then simply applying the value to a backing store.
Here is a code sample when the check is quite useful:
public class MyClass {
...
int ageValue = 0;
public int AgeValue {
get {
return ageValue
}
protected set {
... // value validation here
// your code starts
if (value != ageValue) {
ageValue = value;
}
// your code ends
else
return; // do nothing since value == ageValue
// ageValue has been changed
// Time (or / and memory) consuming process
SaveToRDBMS();
InvalidateCache();
...
}
}
...
More natural implementation, however, is to check in the very beginning in order to avoid unnecessary computation.
protected set {
if (ageValue == value)
return;
... // value validation here
ageValue = value;
// ageValue has been changed
// Time (or / and memory) consuming process
SaveToRDBMS();
InvalidateCache();
...
}
I've actually coded stuff like this a few times, for different reasons. They're kinda hard to explain, so bear with me.
The main thing is that you don't set a new reference if the value at the reference is logically equal to the prior reference's value. In comments above, users have criticized the obnoxiousness of this scenario – and it is obnoxious to have to deal with – but still essentially necessary in cases.
I'd try to split up use cases like this:
The value is an abstract data type, where you may have different constructed instances representing the same logical value.
The reference of value is useful to a caching logic.
You're using a reactive evaluator, where setting a new value may forces a chain-reaction of updates.
The big conceptual point is that, in some cases, you can have the same logical value stored at different references, but you want to try to minimize the number of degenerate references for two big reasons:
Having the same logical value stored multiple times hogs more memory.
A lot of the run-time can use reference-checking as a shortcut, e.g. through caching, which can be more efficient if you avoid allowing redundant references to the same logical value to propagate.
For another random example, .NET's garbage collector is "generational", meaning that it puts more effort into checking if a value can be collected when it's newer. So, the garbage collector can experience gains if you preferentially retain the older reference, as it's in a more privileged generation, allowing the newer reference to get garbage collected sooner.
Another use case, again with abstract data types, is where you might have lazily-evaluated properties attached to them. For example, say you have an abstract class Number that has properties like .IsRational, .IsEven, etc.. Then, you might not calculate those immediately, but rather generate them on-demand, caching the results. In a scenario like this, you may tend to prefer to retain older Number's of the same logical value as they may have more stuff attached to them, whereas a new value may have less information associated with it, even if it's logically ==.
It's kinda hard to think of how to sum up the various reasons why this can make sense in some cases, but it's basically an optimization that can make sense if you have a reason to use it. If you don't have any reason to use it, then probably best to not worry about it until some motivation arises.
The performance is not a big deal, just depends on your logic needs.