Introduction
As a new VB developer, I am not sure you have encountered an application leveraging some of the fundamentals of the VB.NET implementation. Specifically, the difference between the keywords Shadows
and Overrides
. This article, hopefully, will assist you in minimizing your learning curve.
Background
Before the .NET craze, there was a strong following to Visual Basic in the business world, and C++ in the more academic communities. The interesting core difference between these two languages was the fundamental design principle that molded their development. C++'s guiding principle was "Keep the runtime small, and assume a genius developer is behind the keyboard". Visual Basic's core was "Rapid development, assuming average developers". At this point, I have started the ever-lasting VB vs. C flame war. Please hold off for a moment before casting a fireball spell on me. The design goals of the languages were different, not bad - just different. Due to these design principles, VB had a fairly large set of runtime functionality; therefore, strings were native in VB and pointers were discouraged. In C++, in contrast, strings were external while pointers were first class objects. As a result, VB of old did not support many of the object oriented principles as C++, specifically: inheritance and multithreading (Visual Basic 2007). VB.NET has reconciled that drawback, and thus we have the C#, VB.NET religious wars.
Basics
…
Public Class Invoice
Public Sub ProcessInvoice()
…
End Sub
End Class
Public Class TimeMaterials
Inherits Invoice
Public Overloads Sub ProcessInvoice(Invoice as Int)
…
End Sub
End Class
…
VB.NET with its new features needed new nomenclature. However, before we can discuss the solution, we should understand what challenges are they trying to solve. Assume I have an object, Invoice
, which has a function ProcessInvoice
. Moreover, assume that I wish to derive a child from Invoice
, TimeMaterialsInvoice
, which also has a ProcessInvoice
function, review Snippet 1. Elsewhere in code, I have a snippet which looks as follows:
…
Dim bill as Invoice = new TimeMaterialsInvoice()
Bill.ProcessInvoice()
…
Problem
As a brilliant young complier, what am I to do? Of course, I widen the TimeMaterialsInvoice
object bill to simulate the Invoice
class. However, I know there are two implementations of ProcessInvoice
, and I know that this code has the capability to access both of them. So as a computer, this ambiguity confounds me; therefore, I must hack an error loogie on the user! And the user must solve my problem.
Solutions
Ultimately, there are only a handful of solutions: the user wishes to call the base class method, the user wishes to have the freedom to call either function, or the user wishes to call the instantiated version. First, if the user wishes to call the Invoice
function, then the TimeMaterialsInvoice
code should have used the Shadows
keyword. Thus, the TimeMaterialsInvoice
code will not be invoked. An alternative approach, although it will generate warnings, is to remove all modifiers from both functions because the VB.NET compiler assumes the Shadows
keyword applies to the TimeMaterialsInvoice
method.
If the consumer wants to call the Invoice
function some of the time and TimeMaterialsInvoice
method other times, it can be achieved with function signatures; in other words, based on the best argument fit. The complier would use an educated guess to choose the correct implementation. Unfortunately, since, both versions of ProcessInvoice
have the same signature, in this case, this is not an option (see Appendix).
If the consumer wishes to invoke the TimeMaterialsInvoice
method, either the client code or the base class must be aware of the child class. Assuming the client code is aware of the child definition, then the solution to invoke the child ProcessInvoice()
is simple; change the definition of the object to the following:
Dim bill as TimeMaterialsInvoice = new TimeMaterialsInvoice()
However, this may not be desirable because this forces the client to use the single TimeMaterialsInvoice
implementation. It is generally a best practice to code against the most generic interface or base class that defines the desired response. Therefore, the client code should look as follows:
Dim bill as Invoice = new TimeMaterialsInvoice()
Note: the more generic definition of our object. In order to use this syntax, and have the effect of calling the TimeMaterialsInvoice
version of ProcessInvoice
, we need to add the keywords Overridable
and Overrides
:
…
Public Class Invoice
Public Overridable Sub ProcessInvoice()
…
End Sub
End Class
Public Class TimeMaterials
Inherits Invoice
Public Overrides Sub ProcessInvoice(Invoice as Int)
…
End Sub
End Class
The keyword Overridable
in the base class gives the complier permission to replace the said function with a child implementation. Similarly, the keyword Overrides
informs the complier this function will be overriding the original function of the same name.
Conceptually, there is no difference between Shadows
and Overrides
, as they both alter the invocation tree; however, they are fundamentally different in their solution. Recall our example:
…
Dim bill as Invoice = new TimeMaterialsInvoice()
Bill.ProcessInvoice()
…
Bill
's type is of Invoice
, while its implementation is of TimeMaterialsInvoice
. In general, Shadows
assumes the function associated with the type is invoked, while Overrides
assumes the object implementation is executed.
Appendix – Other language implementations
Ironically, all of these same challenges exist in C#, Java, and any other OOP programming language.
VB.NET
|
C#
|
Shadows
|
new
|
Overloads
|
-
|
Overrides
|
override
|
Overridable
|
virtual
|
Note: Regarding Overloads
The keyword Overloads
, although is used during the class design time, enables a very different syntactical result, when compared to Shadows
or Overrides
. Formally, overloading is creating many definitions with the same name; therefore, to tell them apart, the compiler requires them to have different method signatures. The VB.NET complier, for reasons of clarity, decided to require the Overloads
keyword, as in Snippet 2, to expose both implementations to the class consumer. A real-life example of this would be the DateTime.ToString
function. An alternative overloaded option is DateTime.ToString(String)
, where the String
argument is a formatting option. If the consumer of DateTime
wishes for the defaults, the first implementation is elected. In contrast, if the consumer wishes to make his formatting explicit, he could choose the second by submitting a String
argument.
…
Public Class Invoice
Public Sub ProcessInvoice()
…
End Sub
End Class
Public Class TimeMaterials
Inherits Invoice
Public Overloads Sub ProcessInvoice(Invoice as Int)
…
End Sub
End Class
…
Revision log
02-01-07
02-15-07
- Altered C# cross references, based on Mr. Menski's suggestions.
- Made hyperlinks functional.
Bibliography
- Killian, G. (2003, August 23). Digesting Shadows vs. Overrides. Retrieved January 27, 2007, from Code Better: http://dotnetjunkies.com/WebLog/grant.killian/archive/2003/08/24/1225.aspx.
- Object-oriented programming. (2007 , January 29). Retrieved 01, 29, 2007, from Wikipedia: http://en.wikipedia.org/wiki/Object-oriented_programming.
- Visual Basic. (2007, January 24). Retrieved January 29, 2007, from Wikipedia: http://en.wikipedia.org/wiki/Visual_basic_6.
- Visual Basic Language Concepts: Shadowing (n.d.). Retrieved January 20, 2007, from MSDN Home: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcn7/html/vbconshadowing.asp.