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
- Anonymous
August 08, 2005
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... - Anonymous
August 09, 2005
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. - Anonymous
August 09, 2005
The comment has been removed - Anonymous
August 09, 2005
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!!! - Anonymous
August 14, 2005
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