NEW & IMPROVED: The "Unset" Enum Item

This hidden feature of VBA lets you take advantage of my "Unset" enum item technique without cluttering up your IntelliSense.

NEW & IMPROVED: The "Unset" Enum Item

I wrote previously about the benefits of using an "Unset" enum item:

The “Unset” Enum Item
This simple technique is a foolproof way to avoid the sort of logic bug that can live undetected in your codebase for years.
Private Enum pp__PaymentPeriod
    pp_Unset
    pp_Discount
    pp_Face
    pp_Penalty
End Enum

Private Function CalcAmtOwed(BaseAmt As Currency, _
                             PaymentPeriod As pp__PaymentPeriod)
    Select Case PaymentPeriod
    Case pp_Unset
        Throw "PaymentPeriod value never set"
    Case pp_Discount
        CalcAmtOwed = Round(BaseAmt * 0.98, 2)
    Case pp_Face
        CalcAmtOwed = BaseAmt
    Case pp_Penalty
        CalcAmtOwed = Round(BaseAmt * 1.1, 2)
    Case Else
        Throw "Invalid PaymentPeriod: {0}", PaymentPeriod
    End Select
    
End Function


Sub SafeCalc()
    Dim PmtPeriod As pp__PaymentPeriod
    
    Debug.Print CalcAmtOwed(100, PmtPeriod)
End Sub
A SAFER way to work with enums.

The one annoying thing about this technique is that the "Unset" item pollutes our IntelliSense:

We rarely–if ever–will want to explicitly set the PmtPeriod variable to "Unset".

That enum item exists only as a placeholder to throw an error in case we forget to assign a value to the PmtPeriod value. Or, more likely, an unexpected code path leads to the assignment operation being skipped altogether.

Ideally, we would not see the "Unset" option in the IntelliSense dropdown at all.

Hiding the "Unset" Enum Item

It turns out there is a way to make that happen using a hidden feature of VBA:

Naming an enum item with a leading underscore makes it a hidden member.

SIDE NOTE: We need to wrap the underscore-prefixed identifier in square brackets. Starting an identifier with an underscore is illegal in most VBA syntax. The square brackets act sort of like escape characters within the enum definition. However, the square brackets do not allow you to start any identifier with an underscore.  I tested naming a Sub and a local variable with a leading underscore. Both attempts failed with compile errors, even with the enclosing square brackets.

Here's the updated code:

Private Enum pp__PaymentPeriod
    [_pp_Unset]         '<-- You need the square brackets here...
    pp_Discount
    pp_Face
    pp_Penalty
End Enum

Private Function CalcAmtOwed(BaseAmt As Currency, _
                             PaymentPeriod As pp__PaymentPeriod)
    Select Case PaymentPeriod
    Case [_pp_Unset]    '<-- ...and here...
        Throw "PaymentPeriod value never set"
    Case pp_Discount
        CalcAmtOwed = Round(BaseAmt * 0.98, 2)
    Case pp_Face
        CalcAmtOwed = BaseAmt
    Case pp_Penalty
        CalcAmtOwed = Round(BaseAmt * 1.1, 2)
    Case Else
        Throw "Invalid PaymentPeriod: {0}", PaymentPeriod
    End Select
    
End Function


Sub SafeCalc()
    Dim PmtPeriod As pp__PaymentPeriod
    PmtPeriod = pp_Discount
    
    Debug.Print CalcAmtOwed(100, PmtPeriod)
    
    PmtPeriod = [_pp_Unset]   '<- ...and also here
End Sub

Cleaner IntelliSense

The payoff is in the IntelliSense dropdown as shown below:

Hidden Members

There's nothing particularly magical about the disappearing member.  It's not completely gone.  In fact, if you turn on "Show Hidden Members" by right-clicking in the Object Browser, the Unset item will reappear in the IntelliSense dropdown.  The item will appear in a dark gray font to distinguish it from visible members.


Addendum: Runway Motion Brush

Speaking of new & improved, I used Runway's motion brush AI tool to bring the bird from the cover image to life.  Click on the image below to see the four-second video.  We are living in wild times...

Image by Capri23auto from Pixabay

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