PascalCase All the Things

There is only one correct capitalization convention in VBA: PascalCase.

PascalCase All the Things

Matthieu Guindon addresses this issue in his most excellent Rubberduck Style Guide:

Use PascalCase if you like. Use camelCase if you like. Consistency is what you want to shoot for, and in a case-insensitive language that only stores a single version of any identifier name it’s much easier and simpler to just use PascalCase everywhere and move on to more interesting things.

I wholeheartedly agree with (almost) all of this passage.  My lone quibble?  

In the context of VBA, PascalCase is clearly superior to camelCase.  

3 Reasons to Prefer PascalCase

  1. VBA's Case-Changing "Feature"
  2. Version Control
  3. Consistency with VBA

VBA's Case-Changing "Feature"

Many languages (such as Java) have a convention where classes are named with PascalCase (e.g., MyClass) and instances of those classes have the same name but in camelCase (e.g., myClass).

Here's what a Java developer might want to do in VBA:

Dim myClass As MyClass
Set myClass = New MyClass

Unfortunately, this won't work in VBA.  VBA has a "feature" whereby every identifier in an entire project has its capitalization changed to match the most recent declaration of that identifier, regardless of scope.

VBA’s Case Changing “Feature”
VBA likes to change the casing of our code (upper/lower/mixed). It may seem random, but it’s not. Read all the details here.

Regardless of the capitalization of the class module itself, using camelCase to declare the object variable will result in every myClass identifier in the project being set to camelCase.  

If you tried entering the above lines of code into the VBA editor, this is what they would end up looking like:

Dim myClass As myClass
Set myClass = New myClass

I should mention that the above code is legal VBA.  The parser is smart enough to distinguish that when myClass appears on the left side of the lines above that it is referring to an object variable and when it appears on the right side it is referring to the class module.  

But great programmers write code that humans can understand, and the example above is hopelessly confusing.

Version Control

This case-changing feature in and of itself is not a huge deal.  After all, VBA is a case-insensitive language.  The real problem comes in when you incorporate version control (you are using version control, right?).

Git and Mercurial are both case-sensitive.

This means that any time the identifiers in your code change capitalization, Git will see that as a change (even though the program's behavior remains the same).  At the extreme, changing a single letter of code could trigger a potential avalanche of changes in version control.

Don't believe me?  

Try changing Dim i As Integer to Dim I As Integer then export all your code to version control.

Assuming you're like the rest of the entire programming world, your code is chock full of loop index variables named i.  Changing the declaration of just one of them to a capital I will force every other instance of i to become I instantly.  Every. Single. One.

Since VBA itself is not case sensitive, all of those changes are false positives.  The casing of the code may have changed, but its behavior did not.  False positives reduce signal-to-noise ratio and make it much harder to review the intentional changes you made to your code.

Consistency with VBA

VBA's standard library uses PascalCase for all of its function names, as do all of the Office application libraries.

This means that even if you wanted to use camelCase, the combination of VBA's case-changing "feature" and the existence of PascalCase identifiers in all the Microsoft libraries would be a disaster waiting to happen.

Imagine you have used the built-in Day() function in several places throughout your code; I use it myself all the time (ShiftDate(), IsEndOfYear(), etc.).  What if you then declare a variable day somewhere (anywhere) in your project?  That's right, it will change every other identifier to day including every identifier used to refer to the VBA library function.

Check out this BEFORE and AFTER example:

'https://nolongerset.com/convenience-date-functions/
Function IsEndOfYear(DateToCheck As Date) As Boolean
    IsEndOfYear = (Month(DateToCheck) = 12 And Day(DateToCheck) = 31)
End Function
My IsEndOfYear() function uses the Day function from the standard VBA library.

Here's what happens to the above code if we declare a local variable day anywhere else in the project:

Function IsEndOfYear(DateToCheck As Date) As Boolean
    IsEndOfYear = (Month(DateToCheck) = 12 And day(DateToCheck) = 31)
End Function

Sub SampleSub()
    Dim day As String
End Sub
Notice that by declaring the variable day as lower-case in the SampleSub() that it changes the casing of the Day function from the standard VBA library to day() in the IsEndOfYear() function (which was outside the scope of the declaration made in SampleSub()).

Exceptions to the Rule

As a general rule of thumb, you can break the PascalCase rule if the identifier will not collide with a different identifier that may be in PascalCase.

  • Prefixes
  • Single-letter variables
  • Enums

Prefixes

Using lower-case letters for prefixes enhances readability by conveying special characteristics of the identifier.

This is one reason why I loathe System Hungarian notation, where the variable's type information is embedded in its name.  When every variable begins with a lower-case letter, "special" variables–such as those with module-level scope or global scope–fail to stand out.  

While System Hungarian is an abomination, Apps Hungarian is a different story.  I use it myself to distinguish between variables that hold different parts of a file name.  For example, SourcePath is ambiguous.  Does it hold the full path to the source file or just the file name?  I use a consistent Apps-Hungarian-style prefix to distinguish the two:

  • fpSource: full path to the source file
  • fnSource: source file's name (without the path)

Here's some sample code demonstrating various common identifier prefixes:

Option Explicit

Public gMyGlobal As String

Private mMyModuleLevelValue As Long

Sub UpdateTemplateText(TemplateID As Long, fpSource As String)
    'https://nolongerset.com/vba-file-system-naming-convention/
    Debug.Print "Full path of source text: "; fpSource
    
    'https://nolongerset.com/parameterized-constructors-in-vba/
    Dim Template As oTemplate
    Set Template = NewTemplateObject(TemplateID)
    
    'https://nolongerset.com/text-files-read-write-append/
    Template.UpdateText FileRead(fpSource)    
End Sub

Single-Letter Local Variables

Single-letter variables should always be declared as lower-case letters.

Dim i As Integer, s As String

Capitalizing a single-letter variable doubles the effort to type it because now it takes two key presses ([Shift] + the letter itself) rather than one.  It also does nothing to enhance readability of the code, so it has no benefit.  

I use the term "local variable" rather than the more general term "identifier" purposely: single letters provide no semantic meaning beyond their immediate context.  They can enhance readability by minimizing noise when used in the right circumstances (e.g., using s to build a multi-line string), but their purpose should be abundantly clear.

Enum Types

I use lower-case prefixes with my preferred Enum naming convention.  

Public Enum env__Environment
    env_UNSET
    env_Development
    env_Test
    env_Production
End Enum

I get away with this by incorporating underscores into the identifiers.  Since I only use underscores with enums, I can guarantee there won't be any collisions with other types of identifiers (e.g., procedure names, variable names, etc.).

What About Constants?

Many programming style guides recommend using all-caps when defining constants, especially global constants.

There are a few problems with that advice for VBA, though.  First, there's a strong possibility of collisions with other identifiers.  One way to avoid that is to use underscores in your global constant names.  That's an unsatisfying solution for a couple of reasons:

  1. A single-word constant name will have no underscores; forcing a second word can lead to an awkward name or, at the very least, one that is longer than necessary
  2. I reserve underscores for my enum naming convention, so I avoid them in all other identifiers–including constants

So, how do I name my global constants?

I use a global class with a predeclared ID named "C":

Debug.Print C.MyGlobalConstant
Better Global Constants in VBA with Dot-Driven Development
My global constant “C” class--with PredeclaredId = True--is a great alternative to traditionally-declared global Public Const’s.

I suppose this breaks my lower-case-only single-letter naming convention, but, hey, nobody's perfect. ¯\_(ツ)_/¯

Cover image created with Microsoft Designer

All original code samples by Mike Wolfe are licensed under CC BY 4.0