Overriding, Covariance, Contravariance

As we've already mentioned, C# requires any method that is overridden to be declared virtual, and any method that overrides another to be declared with the modifier override. We handle this by analyzing the class hierarchy and recording the analysis in the digest XML file, which is available to the stylesheet that generates the C# code.

In addition, Java allows an overriding method to have a covariant return type: if Expression.evaluate() returns Sequence, then Arithmetic.evaluate() can return AtomicValue, given that AtomicValue is a subclass of Sequence. C# doesn't allow covariant return types until version 9.0 of the language, and we decided this was a new promised feature that we would be unwise to rely on. Instead:

Java allows interfaces to define default implementations for methods; C# does not. The transpiler handles default method implementations by copying them into each subclass. This of course can lead to a lot of code duplication, so we have eliminated some of the cases where we were using default methods unnecessarily.