One of the biggest shifts for most developers migrating to the Microsoft .NET Framework involves the underlying programming paradigm. Although C++ developers have always worked in an object-oriented (OO) environment, most other developers have worked in what can be termed an object-based environment. This difference might not seem significant, but the real challenge comes in understanding some of the concepts that a true OO environment, such as the .NET Framework, introduces.
Many people wonder why Visual Basic .NET isn't backward-compatible with Visual Basic (VB) 6.0. Although transitioning VB 6.0's runtime environment to the .NET Framework might have been possible, the underlying paradigm shift mandated that VB undertake a massive transformation. This underlying shift, and not any specific syntax changes, prevents backward compatibility. As an object-based environment, VB 6.0 is limited in access to concepts such as inheritance, overloading, and overriding. Just like C++, Lisp, Smalltalk, and other OO languages, Visual Basic .NET (and every .NET language) takes full advantage of OO concepts.
To discuss some of OOP's inherent features, we all need to be on the same page with some of these concepts, starting with the concept of an object. An object has a set of data (i.e., properties) and behaviors (i.e., methods) associated with that data. For example, consider a table of employees in a database. Although this table has certain data that defines the employees, it doesn't have any behaviors. That's where classes come into play. You can create a class that persists the data associated with the employees (i.e., persists the properties) and that provides a set of behaviors that control how to manipulate the data (i.e., provides the methods).
So far, this definition of an object describes how objects behave in object-based environments, such as VB 6.0. However, this definition doesn't describe how objects behave in an OO environment. The object that I've described thus far has more in common with a procedural language than an OO language. Objects in object-based languages are complete packages—everything that describes the implementation of the object is self-contained. One object doesn't share its implementation with any other objects. More important, no native way exists to group a set of objects as a generic type. The ability to group a set of classes under a generic class is at the heart of OOP.
With VB 6.0, you can create an employee object, but that object can't act like a person unless you write code. Although you can use a concept called interface inheritance to put a wrapper on the object so that you can treat the object as a person, this wrapper doesn't automatically give you the same behavior because every object must implement its own version of that wrapper. So, although VB 6.0 uses objects, you can't automatically create specific objects as part of a generic definition. However, in OOP, you can have a generic definition define a behavior that, when called, will look at the specific type of object and call the correct implementation method for that behavior.
OO terms such as polymorphism, inheritance, overloading, and overriding describe the ability to group classes under more generic classes and manage the implementation of both the specific and the more generic classes. Polymorphism is generally the scariest of these terms, but in many ways, it's the simplest to understand. According to Merriam-Webster OnLine (http://www.m-w.com), polymorphism is "the quality or state of being able to assume different forms." So, if you can treat the employee object as a person, then the object is polymorphic. Using interface inheritance, you already have this ability to a limited extent. However, polymorphism extends this ability because you can use inheritance instead of explicitly implementing each object's different form. (For more information about polymorphism, go to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconimplementinginterfacesincomponents.asp.)
Inheritance means that you can say, in the initial class declaration, that a class is derived from a more generic class. For example, an employee IS A person—the "ISA" test is the key to inheritance. Thus, employees are simply a specific type of person; as such, you can use the behavior and properties associated with people without needing to reimplement that logic. You can even create a group called supervisors that are employees, which means that the supervisors are also people. Thus, you can treat supervisors as people.
An important point to remember about inheritance is that when you manipulate the object’s type, you don't risk losing any data because the object never loses its original type. For example, when the system implements polymorphism, the system doesn't change the underlying behavior or data; it simply limits what's exposed to the methods and properties associated with the current type. Polymorphism is just a temporary transformation, or "cast," from the object's actual type to one of the base classes that help define the object.
To manage all this movement within a generic type, you use overloading and overriding. Generally, overloading and overriding are associated with the way objects within the same class structure expose methods. At the top of the class structure, the person class might have a CreateNew method. Because the person class has no idea that employees or supervisors exist, it might require only a name to create a new person. Because the person class has the method, the employee class—which inherits from the person class—also has this method.
Overriding comes into play when you want to change a method. Suppose you want to create employee objects by specifying an employee number rather than a person's name. The person object doesn't know about employee numbers, so you need to create a function with the same name "CreateNew" within the employee class. After you create this function, you can create an employee object by calling the employee class's CreateNew function and specifying an employee number.
Earlier, I noted that with polymorphism, the object doesn't change when you cast it to a parent (or base) type. This concept is important in overriding. When you override a method, even if the object has been cast as a base class, the base class knows that the more specific class might have reimplemented this method. If the base class finds a reimplemented method in the more specific class, the base class will call the specific class's version of the method. For example, suppose an application declares a new instance of an employee, then passes this employee to a generic function that handles creating new people. The generic function is unaware that an employee object exists. When that generic function passes in the name of the new person, the object will recognize that it is really an employee (a specific type of person) and call the CreateNew function.
Overriding relies on the fact that with polymorphism, the actual class is part of the object's definition. Even when you designate an object as a more generic version of itself, the actual object still has a reference to its specific type. In this respect, overriding differs greatly from overloading.
Overloading doesn't make a function available through polymorphism; instead, it lets you specialize the methods that originate in the base class. For example, with overloading, you might create a CreateNew function in the employee class that accepts both the person's name and the employee number. Of course, the person class has no concept of employee numbers, so it can't reference this member function.
Unfortunately for VB developers, the implementation syntax for many OO concepts varies greatly between Visual Basic .NET and the other .NET languages. The result is that in future commentaries, I'll often provide two versions of the implementation for concepts such as inheritance, overriding, and overloading. Introducing each concept deserves a column of its own, so I'll be covering these concepts in detail in the coming weeks. However, next week, I'll discuss the construction and destruction of objects. Although the .NET garbage collector is great, you still need to know how to clean up resources before the garbage collector takes out the trash.