Friday, September 12, 2008

Simulating covariant return types

For several years, Microsoft engineers have refused to add support for covariant return types, a trivially simple feature that should have been in the CLR from the beginning.

Suppose you want to write a Clone() method that returns a copy of the current object. If implementing an interface, you can use this workaround in C# that uses explicit interface implementation:
class MyCloneable : ICloneable {
public MyCloneable Clone() { ... }
object ICloneable.Clone() { return Clone(); }
}

The above workaround is okay for implementing an interface, but what if you are writing a class hierarchy, and you want a Clone() method that is virtual but has the appropriate return type?
class BaseNode : ICloneable
{
object ICloneable.Clone() { return Clone(); }
public virtual BaseNode Clone() { ... }
}
class ComplexNode : BaseNode
{
override BaseNode BaseNode.Clone() { return Clone(); } // Error!
public ComplexNode Clone() { ... }
}

Oops, the workaround that you use for interfaces is illegal for class inheritance. There is still a solution, though:
class BaseNode : ICloneable
{
object ICloneable.Clone() { return Clone(); }
public BaseNode Clone() { BaseNode c; Clone(out c); return c; }
protected virtual void Clone(out BaseNode clone) { ... }
}
class ComplexNode : BaseNode
{
public new ComplexNode Clone() { ComplexNode c; Clone(out c); return c; }
protected override void Clone(out BaseNode clone) { clone = Clone(); }
protected virtual void Clone(out ComplexNode clone) { ... }
}

That's right. You need six Clone() methods. The last method is virtual in case you want to make a class derived from ComplexNode, e.g. VeryComplexNode:
class VeryComplexNode : ComplexNode
{
public new VeryComplexNode Clone() { VeryComplexNode c; Clone(out c); return c; }
protected override void Clone(out BaseNode clone) { clone = Clone(); }
protected override void Clone(out ComplexNode clone) { clone = Clone(); }
protected virtual void Clone(out VeryComplexNode clone) { ... }
}

Without covariant return types, you have to to define an additional virtual function for each additional derived class.

0 Comments:

Post a Comment

<< Home