Visual Basic .NET as a Fully Object-Oriented Language

By Rocky Lhotka et al.

When Visual Basic 4.0 was released, it introduced a whole new era of programming for VB. Object-oriented programming was finally a possibility. Unfortunately, few object-oriented features were included in the VB language at that point. Most notably lacking were true implementation inheritance capabilities, one of the key defining criteria for any OO language. VB was also missing a large number of secondary features such as method overloading and overriding, and constructors.

With VB.NET, the VB language finally completes the transition to a fully OO language. We now have full inheritance, along with all of the associated features we'd expect.

While it certainly remains possible to create applications that require the programmer to have no more knowledge of objects in VB.NET than in VB3, these new capabilities are quite pervasive and so at least some basic understanding is required to take full advantage of VB.NET.

VB.NET now supports the four major defining concepts required for a language to be fully object-oriented:

Abstraction

Encapsulation

Polymorphism

Inheritance

In the following article, we'll define and discuss each of these four major object oriented concepts.

Abstraction

VB has supported abstraction since VB4. Abstraction is merely the ability of a language to create "black box" code -- to take a concept and create an abstract representation of that concept within a program. A Customer object, for instance, is an abstract representation of a real-world customer. A Recordset object is an abstract representation of a set of data.Abstraction allows us to recognize how things are similar and ignore differences to think in general terms, and not the specifics. A text box control is an abstraction, because we can place it on a form, and then tailor it to our needs by setting properties. Visual Basic allows us to define abstractions using class modules.

Any language that allows a developer to create a class from which objects can be instantiated meets this criteria, and Visual Basic is no exception. We can easily create a class to represent a customer, essentially providing an abstraction. We can then create instances of that class, where each object can have its own attributes such that it represents a specific customer.

In VB.NET we implement abstraction by creating a class using the Class keyword.

Encapsulation

Perhaps the most important of the object-oriented concepts is that of encapsulation. Encapsulation is the concept that an object should totally separate its interface from its implementation. All the data and implementation code for an object should be entirely hidden behind its interface.

The idea is that we can create an interface (Public methods in a class) and, as long as that interface remains consistent, the application can interact with our objects. This remains true even if we entirely rewrite the code within a given method thus the interface is independent of the implementation.

Encapsulation allows us to hide the internal implementation details of a class. For example, the algorithm we use to find prime numbers might be proprietary. We can expose a simple API to the end user, but we hide all of the logic used for our algorithm by encapsulating it within our class.

This means that an object should completely contain any data it requires, and that it should also contain all the code required to manipulate that data. Programs should interact with our object through an interface, using properties and methods. Client code should never work directly with the data owned by the object.

In object-speak, programs interact with objects by sending messages to the object indicating which method or property they'd like to have invoked. These messages are generated by other objects, or by external sources such as the user. The way the object reacts to these messages is through methods or properties.

Visual Basic has provided full support for encapsulation through class modules since version 4.0. Using these modules, we can create classes that entirely hide their internal data and code, providing a well-established interface of properties and methods to the outside world.

Polymorphism

Likewise, polymorphism was introduced with VB4. Polymorphism is often considered to be directly tied to inheritance (which we'll discuss next). In reality, however, it's independent to a large degree. Polymorphism means that we can have two classes with different implementations or code, but with a common set of methods or properties. We can then write a program that operates upon that interface and doesn't care about which type of object it operates at runtime. For instance, if both Customer and Vendor objects have a Name property, and we can write a routine that calls the Name property regardless of whether we're using a Customer or Vendor object, then we have polymorphism.

To really understand polymorphism we need to explore the concept of a method signature, also sometimes called a prototype. All methods have a signature, which is defined by the method's name and the data types of its parameters.

Polymorphism merely says that we should be able to write some client code that calls methods on an object -- and as long as the object provides our methods with the method signatures we expect, we don't care which class the object was created from.

We can use several techniques to achieve polymorphic behavior:

Late binding

Multiple interfaces

.NET Reflection

Inheritance

Late binding actually allows us to implement "pure" polymorphism at the cost of performance and ease of programming. Through multiple interfaces and inheritance we can also achieve polymorphism with much better performance and ease of programming. Reflection allows us to use either late binding or multiple interfaces, but against objects created in a very dynamic way -- going even so far as to dynamically load a DLL into our application at runtime so we can use its classes.

Inheritance

Inheritance is the concept that a new class can be based on an existing class, inheriting its interface and functionality from the original class. This is done by inheriting these behaviors from the existing class through a process known as subclassing. VB.NET is the first version of VB that supports inheritance. With the introduction of full inheritance, VB is now a fully OBJECT-ORIENTED language by any reasonable definition.

Inheritance is one of the most powerful object-oriented features a language can support. At the same time, inheritance is one of the most dangerous and misused object-oriented features.

Properly used, inheritance allows us to increase the maintainability, readability and reusability of our application, by offering us a clear and concise way to reuse code both via interface and implementation. Improperly used, inheritance allows us to create applications that are very fragile, where a change to a class can cause the entire application to break or require changes.

Inheritance allows us to implement an is-a relationship. In other words, it allows us to implement a new class that is a more specific type of its base class. This means that properly used, inheritance allows us to create child classes that really are the same as the base class.

This is the challenge. Inheritance is not just a mechanism for code reuse. It is a mechanism to create classes that flow naturally from some other class. If we use it anywhere we want code reuse, we'll end up with a real mess on our hands. If we use it anywhere we just want a common interface, but where the child class is not really the same as the base class then we should be using multiple interfaces -- something we discuss in our book.

The question we must ask, when using inheritance, is whether the child class is a more specific version of the base class.

Properly applied, object-oriented design and programming can allow us to create very large and complex applications that remain maintainable and readable over time. However, OO is no magic bullet, and improperly applied these technologies and concepts can create the same hard to maintain code that we might create using procedural or modular design techniques.