Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution:
Mutable and immutable Point objects with Move methods


The first class is the following:

using System;

public class Point {
  private double x, y;

  public Point(double x, double y){
   this.x = x; this.y = y;
  }

  public double Getx (){
    return x;
  }

  public double Gety (){
    return y;
  }

  public  Point  Move(double dx, double dy){
    x += dx; y += dy; 
    return this;
  }

  public override string ToString(){
    return "Point: " + "(" + x + "," + y + ")" + ".";
  }
}

In the client program

using System;

public class Application{

   public static void Main(){
    Point p1 = new Point(1.0, 2.0);
    
    p1.Move(3.0, 4.0).Move(5.0, 6.0);
    Console.WriteLine("{0}", p1);      // Where is p1 located?
  }
}

only a single Point object is involved. As expected, it is moved from (1.0, 2.0) via (4.0, 6.0) to (9.0, 12.0). In the similar version, where Point is implemented as a struct, the problem was that the expression p1.Move(3.0, 4.0) returns a copy of a point, which subsequently is moved. This problem does not occur when we work with classes. The client program only creates a single Point object.

In the next version of the Point class

using System;

public class Point {
  private readonly double x, y;

  public Point(double x, double y){
   this.x = x; this.y = y;
  }

  public double Getx (){
    return x;
  }

  public double Gety (){
    return y;
  }

  public Point Move(double dx, double dy){
    return new Point(x+dx, y+dy);
  }

  public override string ToString(){
    return "Point: " + "(" + x + "," + y + ")" + ".";
  }
}

each Move message creates a new Point object. Therefore, the client class

using System;

public class Application{

   public static void Main(){
     Point p1 = new Point(1.0, 2.0),
           p2;
    
     p2 = p1.Move(3.0, 4.0).Move(5.0, 6.0);
     Console.WriteLine("{0} {1}", p1, p2);
   }

}

creates three instances of class Point. First (1.0, 2.0) is referred from p1. The expression p1.Move(3.0, 4.0) returns a new Point object located at (4.0, 6.0). This point receives the message Move(5.0, 6.0). This allocates the third Point object located at (9.0, 12.0). A reference to this object is assigned to p2. Hereby p2 refers the point located at (9.0, 12.0). The two copies are wasteful and actually not needed.

With use of classes, we do not encounter the same problem as we did with the first version of the struct Point.

All taken together, I recommend the second version of struct Point and the first version of class Point. You should use program immutable types with structs and mutable types with classes.