Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VBA inheritance pattern

Tags:

vba

VBA is COM-based, and COM doesn't do inheritance. But I think I may have a pattern which approximates some aspects of it:

Animal.cls

Public Sub Speak() 
    Err.Raise 418, , "Not supported" 
End Sub 

Dog.cls

Implements Animal 

Private mBase As Animal 

Private Sub Class_Initialize() 
  Set mBase = New Animal 
End Sub 

Private Sub Animal_Speak() 
   Me.Speak 
End Sub 

Public Sub Speak() 
   MsgBox "Woof!" 
End Sub 

Public Property Get Base() As Animal 
    Set Base = mBase 
End Property 

Test.bas

Sub Test() 
    Dim animal As animal: Set animal = New dog 
    Dim dog As dog: Set dog = New dog 
    Dim object As Object: Set object = New dog 

    dog.Speak      ' direct      : Woof! 
    animal.Speak   ' polymorphic : Woof! 
    object.Speak   ' late-bound  : Woof! 
    dog.Base.Speak ' fake upcast : Err 418 
End Sub

So the interface member Animal_Speak implemented in Dog.cls (which is private to prevent it being called directly) forwards the call to the public Speak method, which can either delegate it to the equivalent sub in Animal.cls (to 'inherit') or replace it with something else (to 'override').

Also, the Base property in Dog.cls is exposed in case the caller does actually want the base behaviour (to 'upcast').

(terms in quotes because they're approximations only).

So, my questions are:

  1. Is this a known pattern, and if so, is it prevalent?
  2. Are there any downsides?
like image 801
mansellan Avatar asked Sep 23 '17 01:09

mansellan


People also ask

Does VBA have inheritance?

Implementation Inheritance - Not supported in VBA. This is the ability to inherit method implementation from a base class in a derived class. VBA does not implement derived classes, it exposes the methods that need to be implemented. VBA does not implement interfaces, it exposes the methods that need to be implemented.

Is VBA a OOP?

Visual Basic for Applications (VBA) is an event-driven, object-oriented programming language for writing macros, used for the entire Office suite as well as other applications....


1 Answers

The pattern you're implementing is a form of composition, which is a commonly used surrogate for inheritance, even in languages that support class inheritance. You see inheritance has its downsides, and composition is often preferred over it.

Composition doesn't require interfaces. In fact, whenever you encapsulate an instance of an object in a class, and then expose some (or all) of the inner object's members, you are using composition.

In your specific example, you're composing with an "abstract class" (Animal - the interface), which doesn't make much sense, since an interface isn't meant to be instantiated directly like this:

Set mBase = New Animal

In real code, you could have an IRepository interface, a ProductSqlRepository that implements it (then a SupplierSqlRepository and then an OrderSqlRepository, etc.), and you could compose the implementations with some SqlRepository class that exposes the common functionality that all implementations use, each in their own specific ways: meanwhile the client code only ever needs to know/care about IRepository.


You're discovering the possibilities of polymorphism in VBA, by means of interface inheritance, which is not the same as class inheritance.

With class inheritance, you can have virtual and even abstract methods to override in derived classes.

With .NET-flavored interface inheritance, you can have an interface that extends another interface, and an implementing type can implement just that interface to satisfy the compiler - it exposes the members of all interfaces it's extending.

With VBA-flavored interface inheritance, you get a class that can implement an interface. Or two. Or three. Or more. ...the way COM types do.

And that's.. quite awesome already.

It's called Object Oriented Programming - OOP sits on 4 things:

  • Abstraction
  • Encapsulation
  • Inheritance (sad VBA)
  • Polymorphism

It's a prevalent paradigm in quite a lot of programming languages, such as Java and C#. The ideal OOP code is SOLID, loosely-coupled code that can easily be unit-tested. SOLID principles guide a lot of OOP designs:

  • [S]ingle Responsibility Principle
  • [O]pen/Closed Principle
  • [L]iskov Substitution Principle
  • [I]nterface Segregation Principle
  • [D]ependency Inversion Principle

Despite the lack of inheritance capabilities, VBA can still respect these OOP principles, while embracing its constructorless COM nature. Extensible Logging on Code Review, as well as the follow-up post that implements a DatabaseLogger, make a pretty powerful demonstration of it.

But even without using interfaces, thinking in OOP makes it possible to encapsulate any functionality, and write it in such a way that it's a reusable component. Like this reusable progress indicator that illustrates how you step away from a UI (UserForm, or worksheet) code-behind that runs the show, to getting the UI to be nothing more than an I/O device in your application logic.

By learning OOP with VBA, you're sculpting your thought process and embarking on a journey from a procedural paradigm, to the wonders of object-oriented code. Once you've mastered this, you'll want to expand your experience to full-fledged class inheritance, and discover delegates and anonymous functions, and heck perhaps even look into the Functional Programming paradigm, which is yet another completely different way of thinking about code, like OOP is to procedural.

The VBA IDE, the glorious VBE, unfortunately was last updated back when VB6 was all the rage, and doesn't have much OOP-encouraging features. One could even say that the VBE actively hates OOP:

  • Project Explorer's only folders are module types, so a project with many classes quickly becomes a navigational nightmare.
  • There's no "go to implementation" feature to easily locate an interface's implementations.
  • No refactoring tools.
  • No unit testing.
  • No static code analysis.

To be fair, unit testing and refactoring tools weren't as widespread in 1999 as they are today (AFAIK). Still, the downside of OOP in VBA is the lack of features in the IDE itself.

Fortunately the VBIDE has an extensibility model and supports add-ins. So you can get Rubberduck and have all these features and write OOP code in VBA without constantly raging against the lack of IDE features.

DISCLAIMER: I manage the Rubberduck open-source project, hosted on GitHub.

like image 68
Mathieu Guindon Avatar answered Oct 30 '22 10:10

Mathieu Guindon