Overrides vs Shadows keywords in VB.NET

When most folks come from a VB 6 background (and only VB6) they tend not to quite grasp object oriented programming right off the bat. Its one of the reasons why inheritance topics are fairly common on the Visual Basic .NET forums and newsgroups. Today was no different. I woke up and browsed the MSDN forums to find another such question. The user was asking what the difference between an Overridable method being overriden with the “Overrides” keyword, or an ordinary method being overriden by the “Shadows” keyword.

I decided to write a quick article about this and post it for future reference.

First off, lets define the similarities between these two keywords. Both Shadows and Overrides define a means to decorate our methods so we can redefine the functionality provided by a base class. So if I create a BaseClass, and then create a SubClass that inherits from BaseClass, its possible that I might want to redefine how the base and sub classes behave and interact with one another. While I can use either of these keywords, they are completely different in their orientation.

Let’s jump right into it by writing ourselves a base class. This class will have two methods — one that has an overridable method, and one that uses an ordinary method.

' BaseClass impliments an overridable and ordinary method
Public Class BaseClass
  Public Overridable Sub OverridableSub()
    Console.WriteLine(" BaseClass.OverridableSub() called")
  End Sub
  Public Sub OrdinarySub()
    Console.WriteLine(" BaseClass.OrdinarySub() called")
  End Sub
End Class

When you see the overridable keyword in a piece of Visual Basic code, it is an indicator that the designer of this class intended or expected that this class would be Subclassed (overridden) at some point and that “OverridableSub” was a likely candidate for functionality redefnition. You can also deduce that the designer didn’t intend for OrdinarySub to be overriden.

For a bit of advanced education, lets look at the IL produced by these methods.First off, the OrdinarySub looks like any other subroutine we’ve seen in IL before.

.method public instance void OrdinarySub() cil managed

We have a public instance method. Look what happens, however, with our OverridableSub method signature.

.method public newslot virtual instance void OverridableSub() cil managed

Notice we have two additional method characteristics added : virtual and newslot. The virtual characteristic should be familiar to most C# developers. It indicates that the item can be overridden. With that definition, it should now be obvious to VB.NET developers that this means the method has the Overridable modifier. The second characteristic is newslot which indicates that the method will always get a new slot on the object’s vtable. We’ll get into this more later.

So if we want to test our BaseClass, we might write a piece of code something like this in our Main method:

Module Module1
    Sub Main()
        ' Create an instance of the base class and call it directly
        Console.WriteLine("+ Calling BaseClass Methods")
        Console.WriteLine("--------------------------------------------------")
        Dim bc As New BaseClass
        bc.OverridableSub()
        bc.OrdinarySub()
        Console.ReadLine()
    End Sub
End Module

And of course executing this code we would get our exepcted results as follows:

+ Calling BaseClass Methods
--------------------------------------------------
   BaseClass.OverridableSub() called
   BaseClass.OrdinarySub() called
As you'll notice it states that we executed both of our methods against the BaseClass instance. Sounds great, now let's say we now want to create a class that inherits from BaseClass:

' SubClass impliments an overriden BaseClass with overrides and shadows modifiers
Public Class SubClass
    Inherits BaseClass

    Public Overrides Sub OverridableSub()
        Console.WriteLine("   SubClass.OverridableSub() called")
    End Sub
    Public Shadows Sub OrdinarySub()
        Console.WriteLine("   SubClass.OrdinarySub() called")
    End Sub
End Class

To be able to override both of these methods, and stop the compiler from barking at us, we needed to use the overrides keyword on our OverridableSub and the Shadows keyword on our OrdinarySub. This is obviously because of the way we have implemented these methods in the base class. Shadows is a fairly appropriate word because what we are doing is putting the original method (OrdinarySub) in the proverbial shadow of our new method. Our new method stands over top of the old method and executes any time we call against a direct instance of SubClass. Let’s exand our Main method to execute both our SubClass and our BaseClass to see what the difference is:

Module Module1
    Sub Main()
        ' Create an instance of the base class and call it directly
        Console.WriteLine("+ Calling BaseClass Methods")
        Console.WriteLine("--------------------------------------------------")
        Dim bc As New BaseClass
        bc.OverridableSub()
        bc.OrdinarySub()
        Console.WriteLine()

        ' Create an instance of the sub class and call it directly
        Console.WriteLine("+ Calling SubClass Methods ")
        Console.WriteLine("--------------------------------------------------")
        Dim sc As New SubClass
        sc.OverridableSub()
        sc.OrdinarySub()
        Console.WriteLine()
        Console.ReadLine()
    End Sub
End Module 

It follows that because we’ve overridden both of our methods our output would look as follows:

+ Calling BaseClass Methods
--------------------------------------------------
   BaseClass.OverridableSub() called
   BaseClass.OrdinarySub() called

+ Calling SubClass Methods
--------------------------------------------------
   SubClass.OverridableSub() called
   SubClass.OrdinarySub() called

We now are executing code that executes against a BaseClass instance, and we can tell by the output that we are calling the base class methods. We are also executing code against a SubClass instance and we can tell that this is executing our new functionality because the method states its executing SubClass.OverridableSub() and SubClass.OrdinarySub(), not BaseClass.OverridableSub() and BaseClass.OrdinarySub().OK, so we still haven’t seen a difference. Both of these methods really accomplished the same thing didn’t they? We had a base class behavior and both methods overrode that behavior with our newly created methods, right? True enough, but lets look at the consequential differences when we pass our reference around in different ways. We can see example after example in the framework where a method will take a parameter as a general type, but it really expects us to pass in a more specific type. For instance, if a parameter is typed as an XmlNode, we can pass in XmlElements, XmlAttributes, XmlConfigurationElement etc. The list goes on. Why can we do this? Because generally speaking, if I’m an XmlElement, I am also an XmlNode. An XmlElement is a more specific implementation of an XmlNode, so while the XmlElement has more functionality, it still has the base functionality provided by its inherited type XmlNode. So what happens if we create methods that takes BaseClass as a parameter and we pass in an instance of a SubClass as follows?

' Calls the OverridableSub method of the instance passed to it
Public Sub CallOverridableSub(ByVal instance As BaseClass)
    instance.OverridableSub()
End Sub

' Calls the OrdinarySub method of the instance passed to it
Public Sub CallOrdinarySub(ByVal instance As BaseClass)
    instance.OrdinarySub()
End Sub

Notice that we have too methods that both take an instance of BaseClass, not the more specific SubClass. Additionally, we are calling the OverridableSub() method in one of these methods, and OrdinarySub() in the other. Let’s add more code to our Main method to execute these methods passing in an instance of a SubClass. The full code for our example should look like this:

Module Module1
    Sub Main()
        ' Create an instance of the base class and call it directly
        Console.WriteLine("+ Calling BaseClass Methods")
        Console.WriteLine("--------------------------------------------------")
        Dim bc As New BaseClass
        bc.OverridableSub()
        bc.OrdinarySub()
        Console.WriteLine()

        ' Create an instance of the sub class and call it directly
        Console.WriteLine("+ Calling SubClass Methods ")
        Console.WriteLine("--------------------------------------------------")
        Dim sc As New SubClass
        sc.OverridableSub()
        sc.OrdinarySub()
        Console.WriteLine()

        ' Pass the SubClass instance to a method passed as a BaseClass reference
        Console.WriteLine("+ Calling SubClass Methods passed as BaseClass")
        Console.WriteLine("--------------------------------------------------")
        CallOverridableSub(sc)
        CallOrdinarySub(sc)
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ' Calls the OverridableSub method of the instance passed to it
    Public Sub CallOverridableSub(ByVal instance As BaseClass)
        instance.OverridableSub()
    End Sub

    ' Calls the OrdinarySub method of the instance passed to it
    Public Sub CallOrdinarySub(ByVal instance As BaseClass)
        instance.OrdinarySub()
    End Sub
End Module


' BaseClass impliments an overridable and ordinary method
Public Class BaseClass
    Public Overridable Sub OverridableSub()
        Console.WriteLine("   BaseClass.OverridableSub() called")
    End Sub
    Public Sub OrdinarySub()
        Console.WriteLine("   BaseClass.OrdinarySub() called")
    End Sub
End Class

' SubClass impliments an overriden BaseClass with overrides and shadows modifiers
Public Class SubClass
    Inherits BaseClass

    Public Overrides Sub OverridableSub()
        Console.WriteLine("   SubClass.OverridableSub() called")
    End Sub
    Public Shadows Sub OrdinarySub()
        Console.WriteLine("   SubClass.OrdinarySub() called")
    End Sub
End Class

What happens when we execute our code now?

+ Calling BaseClass Methods
--------------------------------------------------
   BaseClass.OverridableSub() called
   BaseClass.OrdinarySub() called

+ Calling SubClass Methods
--------------------------------------------------
   SubClass.OverridableSub() called
   SubClass.OrdinarySub() called

+ Calling SubClass Methods passed as BaseClass
--------------------------------------------------
   SubClass.OverridableSub() called
   BaseClass.OrdinarySub() called

Notice that we are passing the same instance into both methods. Both methods are accepting “BaseClass”, not “SubClass” as a parameter. Our results are completely different. For our OverridableSub, our SubClass method is still called even though we passed this in as a BaseClass instance. However, for our OrdinarySub that used the Shadows modifier, we are getting results from our BaseClass. That is because of some fundamentals in Object Oriented programming. When we override behavior, its overriden no matter how we pass the class to a parameter (with some exceptions made during type casting). However, when we override using the Shadows modifier, our old functionality is only “lurking in the shadows” — not completely overriden. Remember this when trying to override functionality that wasn’t designed to be overriden as such. Your Shadows modifier may help you out when calling against your SubClass, but not when executing against a BaseClass instance.

Be Sociable, Share!

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Post Navigation