I'm using Visual Studio 2010 + Resharper and it shows a warning on the following code:
if (rect.Contains(point))
{
...
}
rect
is a readonly Rectangle
field, and Resharper shows me this warning:
"Impure Method is called for readonly field of value type."
What are impure methods and why is this warning being shown to me?
First off, Jon, Michael and Jared's answers are essentially correct but I have a few more things I'd like to add to them.
What is meant by an "impure" method?
It is easier to characterize pure methods. A "pure" method has the following characteristics:
For example, Math.Cos
is a pure method. Its output depends only on its input, and the input is not changed by the call.
An impure method is a method which is not pure.
What are some of the dangers of passing readonly structs to impure methods?
There are two that come to mind. The first is the one pointed out by Jon, Michael and Jared, and this is the one that Resharper is warning you about. When you call a method on a struct, we always pass a reference to the variable that is the receiver, in case the method wishes to mutate the variable.
So what if you call such a method on a value, rather than a variable? In that case we make a temporary variable, copy the value into it, and pass a reference to the variable.
A readonly variable is considered a value, because it cannot be mutated outside the constructor. So we are copying the variable to another variable, and the impure method is possibly mutating the copy, when you intend it to mutate the variable.
That's the danger of passing a readonly struct as a receiver. There is also a danger of passing a struct that contains a readonly field. A struct that contains a readonly field is a common practice, but it is essentially writing a cheque that the type system does not have the funds to cash; the "read-only-ness" of a particular variable is determined by the owner of the storage. An instance of a reference type "owns" its own storage, but an instance of a value type does not!
struct S
{
private readonly int x;
public S(int x) { this.x = x; }
public void Badness(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
// This should be the same, right?
Console.WriteLine(this.x);
}
}
One thinks that this.x
is not going to change because x is a readonly field and Badness
is not a constructor. But...
S s = new S(1);
s.Badness(ref s);
... clearly demonstrates the falsity of that. this
and s
refer to the same variable, and that variable is not readonly!