Cook Computing

Covarient Method Arguments

June 1, 2002 Written by Charles Cook

As I mentioned in a previous post, covariant return types are uncontentious: their usage can be statically verified by the compiler and they incur no runtime cost. Covariant method arguments are a different matter: in certain situations their usage cannot be statically verified and the compiler must insert runtime checks. A covariant method argument type is one which is more specialized than the corresponding argument in the base class version of the method. Again two things are varying in the same direction: as the class becomes more derived, an argument in an overidden method become more derived.

Several example classes are need to illustrate covariant arguments. NB this code is pseudo-C# because neither the CLR nor C# support covariant arguments.


class ArgGrandParent 
{
  public virtual void A() {}
}

class ArgParent : ArgGrandParent
{
  public override void A() {}
  public virtual void B() {}
}

class ArgChild : ArgParent
{
  public override void A() {}
  public override void B() {}
  public virtual void C() {}
}

class Parent 
{
  public virtual void DoSomething(ArgParent x) { x.B(); }
}

class Child
{
  // following redefinition of argument is not valid C#
  public override void DoSomething(ArgChild x) { x.C(); }
}

Straightforward usage of covariant arguments is where the derived class is called with derived arguments:


Child child = new Child();
child.DoSomething(new ArgChild());

The call to DoSomething is statically typesafe. The DoSomething in class Child calls method C of the ArgChild instance. However it is very easy to make a call which results in an exception being thrown at runtime:


Parent parent = new Child();
parent.DoSomething(new ArgParent());

DoSomething is virtual so DoSomething in class Child will be called. But this version of DoSomething calls method C of its argument and an exception is thrown: the argument is of type ArgParent which doesnt support method C. This illustrates why a runtime check is necessary in some cases and why coavariant argument types are not necessarily considered a good thing.