Week 4: Notes

overloaded constructors

Constructors may be overloaded, meaning that a class may contain several constructors with different numbers and/or types of arguments.

A constructor may call another constructor; this is called constructor chaining. For example, the second Point constructor below chains to the first:

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

  public Point() : this(0.0, 0.0) {  }

}

static members

A field or method may be static. Static members are shared by all instances of a class.

    class Foo {
      static int x = 1;
      static int y;

      static void inc() { x += 1; }
    }

A static method is invoked on a class, not on an instance:

    Foo.inc();

Static methods may access private members of any instance of their class. For example, we can add a static method to the Point class that compares two Point objects and returns true if they are equal:

  public static bool eq(Point p, Point q) =>
    p.x == q.x && p.y == q.y;

enums

An enum type holds one of a fixed set of constant values:

    enum Suit {
      Club, Diamond, Heart, Spade
    }

To refer to one of these values, prefix it with the type name:

    Suit s = Suit.Diamond;

If you'd like to be able to access an enum's values without the type name prefix, include a using static declaration at the top of your source file:

    using static Suit;

Then you will be able to write, for example:

    Suit s = Diamond;

Internally, an enumerated value is stored as an integer. Each constant in an enum is assigned an integer value, starting from 0. For example, in the enumeration above, Diamond is assigned the value 1.

Explicit conversions exist between each enum type and int in both directions:

    Suit s = Suit.Diamond;
    int i = (int) s;    // convert a Suit to an int
    Suit t = (Suit) i;  // convert an int to a Suit

properties

A property is syntactically like a field, but contains a getter and/or a setter, which are methods that run when the caller retrieves or updates the property's value. Inside the setter, the keyword value refers to the value that is being set.

Here is a partial listing of a class Vector that includes a property length:

class Vector {
  double[] a;
  ...
  
  public int length {
    get {
      return a.Length;
    }
    set {
      a = new double[value];
    }
  }
}

You can use expression syntax to define getters or setters. The length property above could be written as

    public int length {
      get => a.Length;

      set => a = new double[value];
    }

indexers

An indexer allows you to define custom getter and/or setter methods that run when an instance of your class is accessed using the array-like syntax a[i]. For example, we can extend the Vector class above with an indexer that retrieves and sets elements of the underlying array v:

    public double this[int i] {
        get { return a[i]; }
        set { a[i] = value; }
    }

A caller can now invoke this indexer as if v itself were an array:

    Vector v = new Vector(...);
    v[3] = 77.2;
    v[4] = v[5] + 1.0;

The indexer defined above has return type double and uses an index parameter of type int. In general, an indexer may have any return type and any index parameter type.

overloaded operators

You may defined overloaded operators for a class, which redefine the meaning of built-in operators such as + and * when invoked on instances of the class. For example:

    class Vector {
      double[] a;
  
      public Vector(params double[] a) { this.a = a; }
  
      public static Vector operator + (Vector v, Vector w) {
        double[] b = new double[v.a.Length];
        for (int i = 0 ; i < v.a.Length ; ++i)
          b[i] = v.a[i] + w.a[i];
        return new Vector(b);
      }
    }

The operator above can be invoked like this:

    Vector v = new Vector(2.0, 5.0, 10.0);
    Vector w = new Vector(1.0, 3,0, 9.9);
    Vector x = v + w;

An overloaded operator must be public and static.

You may overload most of the built-in operators available in C#, including