PascalCase All the Things
Matthieu Guindon addresses this issue in his most excellent Rubberduck Style Guide:
UsePascalCase
if you like. UsecamelCase
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 usePascalCase
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
- VBA's Case-Changing "Feature"
- Version Control
- 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.
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:
Here's what happens to the above code if we declare a local variable day
anywhere else in the project:
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 filefnSource
: 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:
- 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
- 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
I suppose this breaks my lower-case-only single-letter naming convention, but, hey, nobody's perfect. ¯\_(ツ)_/¯
Cover image created with Microsoft Designer