> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Better Global Constants in VBA with Dot-Driven Development
- URL: https://nolongerset.com/better-global-constants/
- Published: 2023-03-28T03:07:59.000Z
- Updated: 2026-05-08T12:50:50.000Z
- Description: My global constant "C" class--with PredeclaredId = True--is a great alternative to traditionally-declared global Public Const's.
- Author: Mike Wolfe
- Tags: Class Modules, VBA, #Import 2026-05-20 02:59

There are (at least) [five problems](https://nolongerset.com/global-constant-problems/) with using standard global constants in VBA:

1. VBA's case-changing "feature" makes the all-caps convention unreliable
2. Optional parentheses make it hard to distinguish between functions and variables/constants
3. Lack of namespaces hinders discoverability
4. Global namespace pollution
5. It's too easy to add new global constants

I'd like to propose a better way.

## C: The Global Constant Class

I stopped using `Public Const` declarations more than seven years ago.

In their place, I use a class module that holds the sort of global, read-only values that would otherwise be declared using `Public Const` statements. The name of this class module is simply the letter `C` (for **C**onstant). 

Additionally, I set this class module's hidden [**PredeclaredId** attribute](https://nolongerset.com/setpredeclaredid/) to True so that I do not have to declare a new object variable in order to use the class. This lets me treat the class module as a pseudo-namespace (*addressing #3*), which avoids further pollution of the already-crowded VBA global namespace (*addressing #4*).

Every reference to a global constant begins with `C.` optionally followed by the constant's category and then the constant's name. For example:

```vba
Debug.Print C.AppName
Global Constants Sample

Debug.Print C.CountyID.Wayne
64
```

The leading `C.` makes it very obvious that what follows is a global constant (*addressing #2*). This also means we don't have to rely on the traditional all-caps naming convention, since the [VBA IDE actively works against us](https://nolongerset.com/vbas-case-changing-feature/) if we try to do that (*addressing #1*).

The biggest complaint most developers will have is that it it is more difficult to add a new global constant. Instead of a single line of code, such as:

```vba
Public Const APP_NAME As String = "Global Constants Sample"
```

You would need to use a Property Get statement, which is three lines:

```vba
Public Property Get AppName() As String
    AppName = "Global Constants Sample"
End Property
```

However, I propose that this added friction is a *feature not a bug.* [Overuse of global state](https://nolongerset.com/overuse-of-global-state/) is a leading contributor to [technical debt](https://nolongerset.com/sources-of-technical-debt/). Making it harder to add new global constants forces you to evaluate your choice and make sure you've considered alternatives, such as a user-configurable value or a [single-row table](https://nolongerset.com/single-row-table-how-to/) (*addressing #5*).

## Dot-Driven Development

I recently read this term in Mark Seemann's excellent book, *[Code that Fits in Your Head](https://www.amazon.com/Code-That-Fits-Your-Head/dp/0137464401)*. The idea behind **dot-driven development** is that you let the IntelliSense guide you to discovering how an API works.

I have an application used in several PA counties. Certain parts of the application have been customized based on the needs of individual counties. If a new employee wants to know which counties we currently support, they need only type `C.CountyID.` and the IntelliSense will show them a list of available counties and return the CountyID of whichever county they select.

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2023/03/image-57.png)

To make this work, we use a naming convention to add additional global constant "sub-classes". I put sub-classes in quotes so as not to confuse this technique with [subclassing](https://en.wikipedia.org/wiki/Inheritance%5F%28object-oriented%5Fprogramming%29#Subclasses%5Fand%5Fsuperclasses) in the general OOP sense. I simply mean the next level down in our global constant hierarchy.

## Sample Code

Here's sample code for our base `C` class. 

Yours will look completely different, though I highly encourage you to name it a single letter for convenience; both `C`(for constant) or `G` (for global) are good options. The samples below all assume a class named `C`.

### The "C" Class

```vba
' --------------------------------------------------------------------------------------
' Name    : C
' Purpose : Provides dot-driven access to global constants.
' Author  : Mike Wolfe
' Source  : https://nolongerset.com/c-class/
' Date    : 7/24/2015
' Notes   - Making this a class module allows for more explicit scoping and easier
'             discoverability of global constants
'         - Chaining is enabled by calling Property Get on other class objects with
'             constants (class name prefixed with "const" by convention)
'         - The feature that gets around requiring a new declaration of this class is
'             setting the Attribute VB_PredeclaredId = True;
'             see https://nolongerset.com/setpredeclaredid/
' Usage   - No need to declare a New instance of this class, just type "c." and
'             choose from the IntelliSense dropdown list
'---------------------------------------------------------------------------------------
Option Compare Database
Option Explicit

Public Property Get AppName() As String
    AppName = "Global Constants Sample"
End Property

Public Property Get CountyID() As constCountyID
    Set CountyID = New constCountyID
End Property
```

Paste the above code into a new class module and name it `C`.

### The "constCountyID" Class

I like to use statement separator tokens (the colon `:` character) to combine lines when I have [multiple single-line-of-code properties or procedures](https://nolongerset.com/beautiful-blocks-of-boilerplate/). 

```vba
Option Compare Database
Option Explicit

Property Get Adams() As Long: Adams = 1: End Property
Property Get Lackawanna() As Long: Lackawanna = 35: End Property
Property Get Montgomery() As Long: Montgomery = 46: End Property
Property Get Wayne() As Long: Wayne = 64: End Property
```

Paste the above code into a new class module and name it `constCountyID`.

Some programmers don't like that style or are unfamiliar with it. Here's the exact same `constCountyID` class code, but formatted in a more traditional style. Use one or the other, but not both.

```vba
Option Compare Database
Option Explicit

Property Get Adams() As Long
    Adams = 1
End Property

Property Get Lackawanna() As Long
    Lackawanna = 35
End Property

Property Get Montgomery() As Long
    Montgomery = 46
End Property

Property Get Wayne() As Long
    Wayne = 64
End Property
```

Paste the above code into a new class module and name it `constCountyID`. Both samples in this section are functionally equivalent. Use whichever style you prefer, but don't try to use both. Besides, the compiler won't let you even if you try.

## Setting the PredeclaredID Attribute

1. Copy and paste the above "C" Class code into a new **class module**
2. Name the class module `C`
3. Copy and paste the "[Full Code](https://nolongerset.com/setpredeclaredid/#the-full-code)" from my SetPredeclaredID article into a **standard** code module
4. **Save** your code
5. Run the following command in the Immediate window:  
`SetPredeclaredId "C", True`

## One of Steve McConnell's "Reasons to Create a Class"

In Steve McConnell's legendary tome, *[Code Complete: Second Edition](https://www.amazon.com/Code-Complete-Practical-Handbook-Construction-dp-0735619670/dp/0735619670/ref=dp%5Fob%5Ftitle%5Fbk)*, he includes the following paragraph in section 6.4 "Reasons to Create a Class":

> **Hide global data** If you need to use global data, you can hide its implementation details behind a class interface. Working with global data through access routines provides several benefits compared to working with global data directly. You can change the structure of the data without changing your program. You can monitor accesses to the data. The discipline of using access routines also encourages you to think about whether the data is really global; it often becomes apparent that the “global data” is really just object data.

I have been using this technique for over seven years now. I first purchased Steve's book many years ago, though I can't remember exactly when. I honestly don't know whether I learned this technique from Steve's book or whether I stumbled into it independently. Either way, I feel better sharing it with you knowing it's got Steve's implicit blessing.

---

### Referenced articles

[Five Problems Working with Global Constants in VBAWorking with global constants in VBA is unnecessarily difficult, resulting in code that’s harder to read and maintain than it needs to be.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2023/03/global-constant-problems.jpeg)](https://nolongerset.com/global-constant-problems/)

[SetPredeclaredId(): Change the Hidden PredeclaredId Attribute of a VBA Class ModuleThis simple function overcomes the lack of a hidden attribute editor for PredeclaredId values in the VBA development environment.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2022/10/SetPredeclaredId-1-.jpg)](https://nolongerset.com/setpredeclaredid/)

[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.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2020/11/letters-691842_1920.jpg)](https://nolongerset.com/vbas-case-changing-feature/)

*Cover image created with [Microsoft Designer](https://designer.microsoft.com/)*