On why C#’s "abstract-override" is so cool:

Good language design usually results in a few well defined simple primitives that can be combined together in intuitive and intelligent ways.
In contrast, poor language design usually results in many bloated constructs that don’t play well together.

The “abstract” and “override” keywords in C# are a great example of this. They both have simple definitions, but they can be combined to express a more complex concept too.

Let’s say you have a class hierarchy: C derives from B, and B derives from A.  A has an abstract method Foo() and Goo().
Here are 2 scenarios where “abstract override” would come up.
1) Let’s say B only wants to implement  Goo(), and let C implement Foo(). B can mark Foo() as “abstract override”. This clearly advertises that B recognizes Foo() is declared in the base class A, yet it expects another derived class to implement it.

2) Let’s say B wants to force a C to reimplement Foo() instead of using A’s definition of Foo(). B marks Foo() as both override (which means B recognizes Foo() is declared in the base class) and abstract (which means B forces derived class C to provide an implementation; regardless that A already provided an implementation).  This came up in one of my recent blog entries here. In that example, A=TextReader, Foo=ReadLine, B= a helper class, C=some class that wants to implement ReadLine() instead of Read(). Now TextReader already has a default implementation of ReadLine() based on Read(), but we want to go the other way around. We want an implementation of Read() based off a derived classes implementation of ReadLine().  Thus B provides an implementation of Read() that consumes ReadLine(), and then marks ReadLine() as “abstract override” to force C to redefine ReadLine() instead of picking up the one from TextReader.

In summary, “abstract override” is cool not because it’s yet one more language feature to express some complex corner case; it’s cool because it’s not one more language feature. The neat part is that you don’t really need to think about any of this. You just use the individual basic concepts naturally, and the complicated stuff comes together automatically.

Comments (6)

  1. Now, this is also true about using "override" and "virtual", where B can now mark Goo() as "virtual override" and give C the choice of overriding Goo() if it needs to. This is really cool, Thanks Mike. It made me think about new possibilities to use in Inheritance Hierarchy…

  2. Chris Brown says:

    Another point worth mentioning on this topic is; try to only use these inheritance constructs when you actually want to implement an inheritance relationship between classes. People often get into using inheritance to facilitate code reuse without actually realising the implications. In an inheritance relationship the objects are tightly bound together and small changes to the superclass interface (e.g. changing the return type of a public method) could break code that invokes that method on any child classes. Sometimes when class B is NOT a type of class A then a collaboration relationship (where B references A through a local variable) might be more appropriate.

  3. Agreed w/ Chris Brown. Many developers abuse inheritance and then regret it later. If you truly have a construct laid out as Mike has demonstrated, then C# is a beautiful way to get what you want done. I love .NET 🙂

  4. Sarang Datye [MS MVP] says:

    Hey this is really cool. At the end of the day the language is simply made up of keywords that would probably fit on half a page! But what really drives the scene is how one twists these keywords to make it more creatively useable! Way to go…. 🙂 Cheers!!!

  5. Chris Brown comments "…Sometimes when class B is NOT a type of class A then a collaboration relationship…might be more appropriate…". For more information regarding improper use of inheritance, see the paper on the Liskov Substitution Principle by Robert C. Martin at: http://www.objectmentor.com/resources/articles/lsp.pdf