Sunday 5 March 2017

Covariance

Covariance preserves assignment compatibility between derived and base type relationships during polymorphism. That is that via Covariance we can use a more derived object than what we are expecting. take a look at these four classes.

class Person {
    static int runningId = 0;

    public int Id { get; } = runningId++;
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Student : Person {
    public double ClassHours { get; set; }
}

class Employee : Person {
    public double Wage { get; set; }
}

class Teacher : Employee {
    public double TeachingHours { get; set; }
}

we see that in this hierarchy Person is the base class, if we look at the following code

class Program
{
    static void Main(string[] args)
    {
        Person student = new Student();
        Person Teacher = new Teacher();

        //not allowed; Employee does not derive from student
        Student Employee = new Employee(); 
    }
}

we see that we can create an instance of Student or Teacher and assign it to a variable of type Person this is because of Covariance.

If you take a look at our program again

class Program
{
    static void Print(Person p) {
        Console.WriteLine(p.ToString());
    }

    static void Print<T>(T p) {
        Console.WriteLine(p.ToString());
    }

    static void Main(string[] args)
    { 
        Print(new Teacher { Name = "Pawel" });
        Print<Employee>(new Teacher{ Name = "Tomek" });
    }

}

you'll see again that it's covariance that let's us pass more derived objects to functions that expect base types.

now let's take a look at covariance in the context of delegates

class Program
{
    delegate Person GetPersonDelegate();

    static void Main(string[] args)
    {
        GetPersonDelegate gpd = ()=> new Teacher { FirstName = "Mirek"};
        Console.WriteLine(gpd.Invoke().ToString());
    }
}

notice that we've created a GetPersonDelegate definition that returns a "Person", but then when we create an instance of it we assign a Func that returns a Teacher. Again this is covariance, in which we expect a less derived type in this case a "Person", but we return a more derived type an "Employee" however since an employee is a person there's no worries.

Take Away
Covariance is a property of polymorphism that let's us use a fatter or more derived object; for example an "Employee" class as a thinner less derived object for example a "Person"