VBA - new built-in enumerations and backwards compatibility

msoGraphic is an MsoShapeType enumeration that is available in Office PowerPoint 2016 and later (versions which can handle svg graphics). If you attempt to check an MsoShapeType against msoGraphic in earlier versions of Office you will get a compile error - as msoGraphic is not defined (in any module containing Option Explicit). I am handling this by putting this property in a module where Option Explicit is NOT declared - and calling it from anywhere that needs the value of the constant. The module only contains this property (and any other properties that need to handle any other constants in this way).

Public Property Get myMsoGraphic() As Long

If msoGraphic = 0 Then
myMsoGraphic = 28
Else
myMsoGraphic = msoGraphic
End If

End Property


I could of course have just re-declared msoGraphic as a constant with value 28, but best practice seems to be that you should avoid using the actual value and use the enumerate constant instead - in case the value gets changed at some point in the future (which I guess is probably highly unlikely).

Does this seem like the best way to handle this situation?

• "Does this seem like the best way to handle this situation?" Not a bad workaround I guess, did you find any side-effects yet? – Mast Sep 5 '19 at 13:41

Without Option Explicit, the msoGraphic identifier in that property scope is a Variant/Empty; there's an implicit type conversion happening when you do this:

If msoGraphic = 0 Then


Sure vbEmpty will equate to 0, or even vbNullString or "", but that's after converting to a comparable type (Integer, or String). There's a better way.

If IsEmpty(msoGraphic) Then


The IsEmpty function will only ever return True when given a Variant/Empty value - which is exactly what we're dealing with here.

I could of course have just re-declared msoGraphic as a constant with value 28, but best practice seems to be that you should avoid using the actual value and use the enumerate constant instead

One doesn't exclude the other. If you define a public constant in an appropriately named standard module (e.g. OfficeConstants), and use it, then you are adhering to the best practice. What happens then is deliberate shadowing of the MsoShapeType.msoGraphic declaration - something Rubberduck would normally warn about, but with a descriptive @Ignore or @IgnoreModule annotation comment, the intention is clarified, and the static code analysis tool knows to ignore them - and with a link to the official documentation, you ensure the values correctly match the actual documented underlying values for each identifier:

'@IgnoreModule ShadowedDeclaration: these constants are only available in Office 2016+
Option Explicit
'https://docs.microsoft.com/en-us/office/vba/api/office.msoshapetype
Public Const msoGraphic As Long = 28
'...


What you want to avoid, is code like this, where 28 is some magic value that has no clear meaning:

If shapeType = 28 Then


Does this seem like the best way to handle this situation?

The problem is that you can't name your property msoGraphic (well you could, but then you'd have to fully-qualify the msoGraphic constant, and then that wouldn't be compilable, even without Option Explicit), so any code (hopefully with Option Explicit specified) that means to use the name msoGraphic now needs to use myMsoGraphic instead, and that isn't ideal, because it adds to the overall cognitive load: you, future you, and eventual maintainers have to remember to avoid msoGraphic and use myMsoGraphic instead, whereas with a Public Const in a standard module that hides/shadows the constant from the referenced PowerPoint library when it exists, usage is much more seamless.

That said, while VBA is case-insensitive, a camelCase public member clashes with the naming convention of pretty much everything else in your standard libraries - enum members only have a lowercase prefix as a namespace surrogate; every type, method, member, property, procedure, function, constant, in every standard library, uses PascalCase. There's no reason to not make every single one of your own procedures use this naming convention too; also while the my prefix is ubiquitous in so many VB examples, it's not a good prefix to use in actual code.

One last thing:

in case the value gets changed at some point in the future

It won't: MsoShapeType is defined in a shared Office library that isn't only referenced by PowerPoint projects - VBA is ridiculously backward-compatible (line numbers, GoSub/Return statements, Call, Let, DefBool keywords, to name a few should-be-extinct-but-aren't-because-backward-compatibility still-supported language features): there is no way any constant ever released into the wild is ever going to get a new value in any future release. Not going to happen.

• In your '@IgnoreModule annotation you have a semicolon to add some additional info; is this something you can actually do with RubberDuck? I've not been having much success... – Greedo Sep 11 '19 at 11:47
• @Greedo I haven't had any issues doing that, but the grammar rules around annotations have changed recently, did it break (try with a colon)? What does "not having much success" means? Is the annotation getting flagged as illegal or malformed? Please open an issue on the repo with the info - parsing annotations is challenging, because the arguments list needs to parse as such (same rules as a procedure call), but the rest of the comment needs to parse as a comment. – Mathieu Guindon Sep 11 '19 at 12:40
• Interesting, works with a colon, not a semi-colon (not much success = the annotation is being ignored, as if it were an ordinary comment, no illegal annotation inspection, but also no @Ignoring of inspections either). Only posted here because I didn't know what the intended behaviour was – Greedo Sep 11 '19 at 14:06