Does contravariance and covariance means using also the same type?

134 Views Asked by At

I am quite confused. I stumbled upon the signature rules (referred also by B.Liskov in her work), which state:

Contravariance of arguments. m1 and m2 have the same number of arguments. If the list of argument types of m1 is a, and that of m2 is b, then ∀i . ai < bi //meaning that a is subtype of b.

From another teaching material:

For a function type DY→CY to be a subtype of (I.e., substitutable for) DX→CX , we must be covariant in the result type, but contravariant in the argument type!

So does it mean I never do proper subtyping if I use just the same types of arguments and return types? I do not understand whether using the same type also counts, i.e. when I use the same type for both the parent and child class method arguments, is this contravariant?

In other words, as c# does not allow arguments contravariance, does it mean my code is never LSP compliant? As I read that LSP requires that arguments must be contravariant..

class Person
{
}
class Employee: Person
{
}

class PersonRegister
{
   GetJobTitle(Employee e) {return e.JobTitle;}
}

class DeriverRegister: PersonRegister
{
  GetJobTitle(Person p)  //contravariance, using less derived type, cannot be done in C#
}

How this could work if e.g. the less derived type does not have the field required, in this example JobTitle? That is property of an Employee but necessarily of a Person.

1

There are 1 best solutions below

10
On BEST ANSWER
class Person
{
}
class Employee: Person
{
}

class PersonRegister
{
   GetJobTitle(Employee e) {return e.JobTitle;}
}

class DeriverRegister: PersonRegister
{
  GetJobTitle(Person p)  //contravariance, using less derived type, cannot be done in C#
}

You are correct. If you want GetJobTitle in DervierRegister to be considered an override of GetJobTitle from PersonRegister, it must use exactly the same types. You should be allowed to create this method as written, but it shadows the one from PersonRegister and is not considered to be an override. So you can write the above, but

var e = new Employee();
PersonRegister pr = new DervierRegister();
pr.GetJobTitle(e);

Will invoke the method from PersonRegister.

does it mean my code is never LSP compliant?

To the extent that you cannot use covariance and contravariance generally, yes. However, for generic interfaces and delegates, support was added in C# 4.0. And also, as discussed, when speaking formally every type is considered to be a subtype of itself so phrases such as "a is subtype of a" are true for all types a.