VBA Interfaces: The Implements Statement

The VBA Implements statement permits the use of interfaces, a mechanism to build clarity and consistency between multiple classes. As VBA projects grow, interfaces can be a central component of how a developer interacts with classes and custom objects.

Overview

This is the twelfth post in the Tips and Tricks with VBA Classes series. This post discusses the Implements statement, a VBA statement which permits the use of an interface class to interact with custom objects. This post focuses on advanced features associated with VBA classes. If you are not yet familiar with VBA classes, I suggest reading our introductory post.

Example File

The example file continues the series theme of working with country data. We rely on two objects: one which stores a county’s overall population and land area data, while the other stores the population and land area of that country’s capital. Data can be added to each object through two separate forms on the spreadsheet.

Macros must be enabled upon opening.

Concept

An Interface permits multiple classes to share public facing methods and properties. While it’s use in simple programs would be quite rare, complex programs which rely heavily on custom objects have a lot to gain from this feature.

There are two common conceptual uses for this feature.

  1. Two or more classes share common properties between eachother. In the example file, there are two separate classes to record population and land area data for countries and capitals.
  2. Two or more classes need to use the same method with slight variation. In our example file, both the country and capital classes use a similar print procedure, but each procedure prints on a different range.
Schematic showing a basic VBA Interface and how it sits between classes and procedures.
Schematic showing a basic VBA Interface and how it sits between classes and procedures.

VBA Polymorphism

VBA Interfaces can be considered a “light” implementation of polymorphism. Going back to a previous post which introduced VBA classes, polymorphism is one of the four pillars of object oriented programming (OOP). While polymorphism has a broad definition, Interfaces do permit class subtyping. That is, an interface will be converted to its proper class type after its declaration.

Building an Interface

Implementing an interface requires code in four or more modules. An interface module must be built (using a class module template) to host the public facing methods and properties of each class it interacts with. Two or more class modules must be built to utilize the interface. Finally, code within a standard module (part of your general program) must interact with the classes.

Interface Module

The interface module defines how the classes will be accessed within a standard module. Using property and method prototypes, the interface acts as the bridge between VBA procedures (within a standard module) and a custom objects derived from a class.

A few important notes about interface modules:

  • While not required, the generally accepted practice is to begin the name of an interface module with a capital “I”. In the example file, the name “IDataInterface” is given to the module.
  • The interface must contain all properties and members also contained within its underlying classes. Within the interface module, these are known as prototypes. Likewise, all classes supported by an interface must contain all prototype properties and members contained within their interface.
    • Given this, if two classes share the same interface, but have different properties and members, missing properties and members must be added to the individual classes. These “duplicate” classes can be empty, effectively making them useless.

The names given to prototype properties will be used within subroutines and functions to access the underlying classes. No scripting can be contained within these procedures.

In our example file, the name property will return either the name of a country, or the name of a capital.

Within the example file, similar Get and Let properties exist for population and landArea. The file also contains the subroutine printData, which will be used to physically print data on the spreadsheet:

Note that this specific member subroutine contains a boolean parameter. Again this is simply a prototype to interface with a class, so no scripting is required within.

Class Modules

With a few exceptions, class modules supported by interfaces look and behave similarly to standard classes.

The following are exceptions:

  • The very first line of the module must contain the Implements statement (see below) with a reference to the interface class name.
  • Within each class supported by the interface, all properties and method must be preceded with the name of the interface module, followed by an underscore. The property name (after the underscore) must be identical to the prototype property from the interface class.
  • Excluding the underscore between the interface name and the property/member name, no other underscores can exist in the property/member name. E.g. IDataInterface_landArea is acceptable while IDataInterface_land_Area would NOT be acceptable.

The following are examples of a successful and unsuccessful implementation of a interface class.

A correct implementation of a VBA Interface.An incorrect implementation of a VBA Interface.

While the example to the left reflects correct naming conventions, the example to the right has the following errors:

  • Within the CountryGeneral class, two errors exist. First, the IDataInterface_land_Area property does not match the naming convention from its Interface class. The correct name should be IDataInterface_landArea (without the second underscore). Second, even if this did match the interface class, property names within interface structures should not include any extra underscores.
  • Within the CountryGeneral class, the IDataInterface_landArea property is missing. As explained above, even if this specific class were to never use this property, it still must be included for the interface to work.

Unfortunately VBA interfaces are a fairly delicate data structure. You will receive a debug error on the first instance of an interface interacting with an error prone class.

Now lets look at the actual class. Within the very top of the declarations area, the Implements statement must be used to link the class to the interface:

The remainder of the declarations area is standard. An interface will not have an impact on member variables, so there is no consistency requirement for these. The CapitalGeneral class looks similar to this, only changing naming for member variables (mCapitalName, mCapitalPop, mCapitalLandArea)

The Let and Get properties do contain variation with naming. As explained above, the interface name (IDataInterface) and an underscore must precede the property name (population).

Again, the same properties within the CapitalGeneral subroutine simply change naming for member variables.

Both the CountryGeneral class and CapitalGeneral class contain a member subroutine to print data. Similar to properties, the interface name (IDataInterface) and an underscore must precede the member name (printData).

Note that the parameter is included here identically to its prototype member.

Standard Module Implementation

Within the standard module, the classes (objects) must be initially declared as the data type of the interface:

Within the first subroutine that accesses the class (through the Interface), the class (object) must be set as its proper data type — that is, the data type of the interface’s underlying class (line 7):

This procedure accomplishes the following tasks:

  • Variables are declared (lines 3-6)
  • The CountryInterface object is set as the CountryGeneral data type (line 7). Note that this object was initially declared as the interface data type (IDataInterface) in the global declarations area. This provides us with access to all the properties and members of the CountryGeneral class, through the IDataInterface interface.
  • Variables countryName, countryPop, and countryLand area are assigned as properties of the CountryInterface object (lines 13-15).
  • The printData method is called to print the data on the spreadsheet.

Note that even though we set the CountryInterface object to a CountryGeneral data type, we are actually using the property names from the interface (IDataInterface) module. To exemplify, we’re using “CountryInterface.name” instead of “CountryInterface.IDataInterface_name” to access the country name property. This is an advantage of interfaces, as we will use the same property names to access stored data between multiple classes.

Full Modules

Interface Module

Class Modules

Standard Module

Other Notes

In the “Building an Interface” section above, we mentioned that building an interface required code in four or more modules. This included two different classes. As a matter of fact, you could build a VBA interface with code in only 3 modules, assuming the interface were to only interact with a single class. Unless you are planning to expand an interface class’ reach at some point in the future, there’s really no reason to have an interface manage only a single class. Accessing a single class’ properties through an interface is redundant.

Leave a Reply