15

Whilst browsing through some legacy code, I was surprised to encounter an abstract override of a member that was abstract by itself. Basically, something like this:

public abstract class A
{
    public abstract void DoStuff();    
}

public abstract class B : A
{
    public override abstract void DoStuff();  // <--- Why is this supported?
}

public abstract class C : B
{
    public override void DoStuff() => Console.WriteLine("!");    
}

Isn't the distinction between a virtual or abstract member always available to the compiler? Why does C# support this?

(This question is not a duplicate of What is the use of 'abstract override' in C#? because the DoStuff-method in class A is not virtual but abstract as well.)

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Rob Wijkstra
  • 801
  • 1
  • 7
  • 19
  • 6
    See: https://stackoverflow.com/a/8905465/1336590 – Corak Sep 13 '17 at 12:44
  • 1
    in your example `DoStuff method` in class `A` is Abstract, so Abstract override doesn't make sense in Class `B` and is not be necessary, it makes sense when DoStuff in Class `A` is Virtual so you can make it 'abstract override' to force class `C` to implement it – esiprogrammer Sep 13 '17 at 12:49
  • I know that the abstract override doesn't make sense. What I'm asking is *why* C# supports it in the first place. (I want to know if there's added value to it that I'm unaware of) – Rob Wijkstra Sep 13 '17 at 12:57
  • 4
    This surprised me too. See https://ericlippert.com/2011/02/07/strange-but-legal/ – Eric Lippert Sep 13 '17 at 13:00
  • So it makes sense if the original method is virtual. Why spend time and effort to explicitly disallow it if the original method is abstract (and needing to check the whole path up to `object` to see if it isn't virtual *somewhere*)? – Corak Sep 13 '17 at 13:09
  • Suppose the compiler disallowed the case where the base was abstract (not virtual). This would not prevent any errors, but it *would* break the case where the method started off virtual, then was made abstract -- for no reason, as `B` was perfectly content with an abstract method to begin with. – Jeroen Mostert Sep 13 '17 at 13:09
  • 2
    I don't think this is a dupe. The question is not why abstract override is legal, but why override-abstract-of-an-abstract is legal. – Eric Lippert Sep 13 '17 at 13:13
  • And the answer is (1) Implementing that error is work for the compiler team that confers zero benefits to any customer, (2) it's harmless, and (3) as Jeroen points out, it introduces a new kind of brittle base class failure. – Eric Lippert Sep 13 '17 at 13:13

1 Answers1

17

To clarify the question: the question is not "why is an abstract override legal?" An existing question handles that. (See also my blog post on the subject.)

Rather, the question is "why is an abstract override legal when the overridden method is also abstract?"

There are several arguments in favour of not giving an error here.

  1. It's harmless.

  2. To give an error, someone on the compiler team must have thought of this scenario and considered it to be worth the time to design the feature, verify that it doesn't cause any bad interactions with other features, write a detailed specification, implement it, test it, write the documentation, translate the error message into two dozen languages, translate the documentation, and maintain the feature forever. What's the compelling benefit that justifies those costs? I see none.

  3. Whenever something looks weird in C# ask yourself what if the base class was owned by someone not on my team and they like to edit it?

Consider for example a variation on your scenario:

public abstract class Z 
{
  public abstract void DoStuff();
}

public class A : Z
{
    public override void DoStuff() 
    { 
      throw new NotImplementedException(); 
    }
}

public abstract class B : A
{
    public override abstract void DoStuff();
}

The authors of class A realize that they have made a mistake and A and DoStuff should be abstract. Making a class abstract is a breaking change because anyone who says "new A()" is now wrong, but they verify that none of their client teams in their org have created a new A. Similarly, calling base.DoStuff is now wrong. But again, there are none.

So they change their code to your version of class A. Should class B now have a compile time error? Why? There's nothing wrong with B.

Many features of C# that seem odd are there because the designers consider the brittle base class to be an important scenario.

  1. Finally, we should consider what the preconditions are for overriding a method. The overridden method has to be accessible by the overriding code, the overriding code has to be in a derived type, and the overridden method has to be a virtual method in the first place. There are obvious good reasons for those requirements. Introducing another requirement -- overrides require that no more than one of the overriding and overridden method be abstract -- doesn't have a principled reason underlying it.
Brian
  • 25,523
  • 18
  • 82
  • 173
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Wow, I wasn't expecting a reply from Mr. Lippert himself. Especially your third argument makes sense to me. Thanks for taking the time for providing me with such an extensive answer! – Rob Wijkstra Sep 13 '17 at 14:24
  • 1
    @RobWijkstra: You're welcome; thanks for the interesting question. – Eric Lippert Sep 13 '17 at 14:32