Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this method Impure?

Tags:

c#

.net

I read this answer: https://stackoverflow.com/a/9928643/16241

But I obviously don't understand it because I can't figure out why my method is impure. (The method in question is ToExactLocation()).

public struct ScreenLocation
{
    public ScreenLocation(int x, int y):this()
    {
        X = x;
        Y = y;
    }

    public int X { get; set; }
    public int Y { get; set; }

    public ExactLocation ToExactLocation()
    {
        return new ExactLocation {X = this.X, Y = this.Y};
    }

    // Other stuff
}

Incase you need it here is the exact location struct:

public struct ExactLocation
{
    public double X { get; set; }
    public double Y { get; set; }

    // Various Operator Overloads, but no constructor
}

And this is how I call it:

someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation == someScreenLocation.ToExactLocation())
{
     // Do stuff
}

When I do that, ReSharper flags it with "Impure Method is called for readonly field of value type."

Why is it saying that? And what can I do to make it go away?

like image 781
Vaccano Avatar asked Mar 25 '13 03:03

Vaccano


2 Answers

It's not pure because it does not return a value dependent only on its input. When the value of X or Y changes so does the return value of ToExactLocation, i.e., its output depends on internal, mutable state.

Additionally, the setters for X or Y in ExactLocation may mutate the input. The getters of ScreenLocation may as well.

someScreenLocation is a readonly field and is a value type. You are calling ToExactLocation on a value, i.e., a readonly field. When you access a reaodnly value type a copy is created as to avoid mutating the value itself. However, your call may mutate that value, which, in many cases, is not what you want as you will be mutating a copy. This is why you get a warning.

In this case, you can ignore it, but I would avoid mutable value types in general.

EDIT:

Let me attempt to simplify...

struct Point
{
    int X;
    int Y;
    bool Mutate() { X++; Y++; }
}

class Foo
{
    public readonly Point P;
    Foo() 
    { 
        P = new Point();
        P.Mutate();  // impure function on readonly value type
    }
}

When Mutate() is called, a copy of P is created and passed along with the method. Any mutation of P's internal state will be irrelevant as it mutates a copy.

like image 135
Ed S. Avatar answered Sep 24 '22 10:09

Ed S.


One of the conditions of a Pure Method is that its output (return value) is wholly dependent on its input (arguments).

Your .ToExactLocation() method is not pure, because its output depends both on the input arguments and also on the current value of a mutable struct.

Resharper doesn't like this, because mutable structs are bad (don't use them). I expect the error would go away if you either changed your code to use a class instead of a struct or redesigned the struct so the the .X and .Y members could only be set by the constructor.

like image 41
Joel Coehoorn Avatar answered Sep 23 '22 10:09

Joel Coehoorn