Wednesday, June 20, 2007

Beware The Evil Shadow

Evil Shadow Object-oriented programming principles have been an excellent addition to software development but one component that inevitably appears in OO languages has confounded me by it's uselessness. In VB.NET it is known as the "Shadows" modifier, in C# it is found in class member declarations sharing the name "new".

The purpose of this modifier keyword is to allow a subclass to redefine a property, field, or method of the base class where the base class has not been declared "Overridable" or "virtual" in VB.NET or C# respectively. Unfortunately it suffers from a major drawback, as demonstrated by the following code:

class Base
{
   virtual public string Extendable() { return "Extend"; }
   public string Locked() { return "Lock"; }
}

class Foo : Base
{
   override public string Extendable() { return "Food"; }
   new public string Locked() { return "Picked"; }
}

Base b = new Base();
b.Extendable(); // returns "Extend"
b.Locked(); // returns "Lock"

Foo f = new Foo();
f.Extendable(); // returns "Food"
f.Locked(); // returns "Picked"

Base bf = new Foo();
bf.Extendable(); // returns "Food"
bf.Locked(); // returns "Lock" !!!

As you can see, if the Foo methods are called via a Foo-typed variable, there is no difference between shadowing and overriding. However, as soon as you call a Foo method via a Base-typed variable, or pass a Foo instance to another class expecting a Base, you lose the functionality of Foo.

If "new" is omitted from Foo's implementation of Locked, Visual Studio reports an error: The keyword 'new' is required on 'Locked' because it hides method 'Base.Locked()'. It is very easy for someone to simply add the keyword as required with realising the consequences.

Occasionally, all you might want to do is utilise some existing behaviour in a base class and add some more features and shadowing or member hiding is fine. The fact that you have used shadowing is not obvious in the calling code though.

Most of the time, I want to alter the behaviour of a base class and pass my new subclass to existing code, perhaps in the Framework, that is only expecting the base type. Beware.

Thursday, June 21, 2007 4:43:43 AM (Cen. Australia Standard Time, UTC+09:30)
Drawback? That's not a drawback at all. Its completely obvious if you understand how vtables work in .NET. Is this different in any OO language? How'd ya like it if somebody new'd all over your "foo" method, so every time you did "this.foo()" in your class you'd be running some code written by a dope that extended your base class? Uncool. Definitely uncool.
Thursday, June 21, 2007 8:13:59 AM (Cen. Australia Standard Time, UTC+09:30)
Hi McGurk,

Thanks for your comment.

I'm not suggesting that the Shadows/new modifiers or their equivalent in any other language should be changed to allow the developer to forcefully override functionality in a base class that has been marked as non-overridable. That's a whole other blog post. However, to a developer less familiar with the specifics of these modifiers it could misconstrued that it has allowed such an override to occur, especially when the compiler error makes it sound so easy.

Personally, in every situation I've encountered, it would be more readable to use a different name for the new method instead of hiding the base, or in the worst case, it would probably be less fragile to rewrite the required behaviour instead of inheriting it. Ultimately though, the need for shadowing exists solely for the situation of trying to override base functionality that cannot be marked virtual because either someone else wrote it, or it's locked down for version compatibility.
Comments are closed.