HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Enforcing Type with Boiler Plates

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
enforcingwithboilerplatestype

Problem

This is an implementation of Mat's List using by Pseudo-inheriting my Pythonic-List. Inheritance is not built into VBA, but it can be simulated by composing the inherited class and mimicking all it's public methods and members. It's a PITA because a modification of a base class needs to be propagated to all sub-classes.

The implementation is simple, just add a private string data member pTypedName, and whenever the client code tries to add an element where TypeName(Element) <> pTypedName raise a type error.

TypedList

Private Members

Private this As List
Private pTypedName As String


Private Methods

Type Check an element that is being added to a list. If the type has not been set then let this element set the typename. Otherwise, raise an error if it's not the correct type.

Private Sub TypeCheck(ByVal element As Variant, ByVal source As String)

    If pTypedName = vbNullString Then pTypedName = TypeName(element)
    If (TypeName(element) <> pTypedName) Then RaiseTypeError element, source

End Sub


Therefore

Dim tList as New TypedList
tList.Append "A"


Is valid and now tList is of type String.

We also want to check every element in a sequence before we let any of the elements enter the list. If our string list is extended with Array("a", "b", "C", 2) we don't want any of the elements entering the list.

Private Sub TypeCheckSequence(ByVal sequence As Variant, ByVal source As String)

    Dim element As Variant
    For Each element In sequence
        TypeCheck element, source
    Next element

End Sub


The above two methods are boiler plate code at the beginning of any method that sets the data in our TypedList.

This is the error that is raised when it fails.

Private Sub RaiseTypeError(ByVal badItem As Variant, ByVal method As String)
    Err.Raise 13, method, "Element is of type " & TypeName(badItem) & _
                         ", not " & TypedName & "."
End Sub


Enumeration

Note we use this.NewEnum

Solution

All in all I think this looks pretty good. Without proper inheritance, you're pretty much stuck with the boiler plate properties that simply call on the private untyped List's properties. Everything in regards to that was done right, vba just kinda sucks like that.

The only thing I really noticed that I didn't like was the way you're using magic numbers to raise errors.

Err.Raise 9, TypeName(Me) & ".TypedName", _
        "Can only set typename of an empty list."


And

Private Sub RaiseTypeError(ByVal badItem As Variant, ByVal method As String)
    Err.Raise 13, method, "Element is of type " & TypeName(badItem) & _
             ", not " & TypedName & "."
End Sub


First, I find it in consistent to use a sub in one place, but a direct raise in another. I know you're only using error #9 in one place now, but pulling this out will certainly make it easier to use it elsewhere in the future.

But I mentioned the magic numbers didn't I? Normally, I would recommend defining some module scoped constants to make it clear that the code is raising a Subscript out of Range and Type Mismatch error (respectively), but these are built in VB errors we're raising. We're likely to use these in many places in many modules. Given that, I think it's absolutely worth the time to create a module with a public [VbErrorNumbers] Enum. It's some work, but you only ever have to do it once. In fact, I believe I'm going to do this myself later today. A full list of built in VBA errors can be found here.

Code Snippets

Err.Raise 9, TypeName(Me) & ".TypedName", _
        "Can only set typename of an empty list."
Private Sub RaiseTypeError(ByVal badItem As Variant, ByVal method As String)
    Err.Raise 13, method, "Element is of type " & TypeName(badItem) & _
             ", not " & TypedName & "."
End Sub

Context

StackExchange Code Review Q#64004, answer score: 3

Revisions (0)

No revisions yet.