Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The Dark Shadow of Overrides

0.00/5 (No votes)
15 Feb 2007 1  
This article hopefully will assist you in minimizing your learning curve.

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

  • Posted article.

02-15-07

  • Altered C# cross references, based on Mr. Menski's suggestions.
  • Made hyperlinks functional.

Bibliography

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here