1
\$\begingroup\$

I have a CLS_Comparison_Predicate which will take an input value, perform a logical comparison and return a Boolean.

CLS_Compound_Predicate instead takes lists of predicates and an inputValue, and performs MatchAny() or MatchAll() operations on the predicate list.

E.G.

predicate_1 has >= 3
predicate_2 has = 5

MatchAny(6) Returns True
MatchAll(6) Returns False

Thoughts?

Option Explicit

Private predicateList As Variant

Private Const NULL_ERROR_TEXT As String = "Invalid Compare input. Cannot compare against Null"
Private Const OBJECT_ERROR_TEXT As String = "Invalid Compare input. Input must be a value, not an object"
Private Const NOTHING_ERROR_TEXT As String = "Invalid Compare Input. Predicate cannot be Nothing"
Private Const EMPTY_ERROR_TEXT As String = "Invalid Compare Input. Input cannot be empty"
Private Const ZLS_ERROR_TEXT As String = "Invalid Compare Input. Input cannot be a Zero-Length-String"

Public Sub AddPredicate(ByRef inputPredicate As CLS_Comparison_Predicate)

    If inputPredicate Is Nothing Then
        PrintErrorMessage NOTHING_ERROR_TEXT
        Stop
    End If

    If IsEmpty(predicateList) Then
        ReDim predicateList(1 To 1)
        Set predicateList(1) = inputPredicate
    Else
        Dim LB1 As Long, UB1 As Long
        GetBounds LB1, UB1

        ReDim Preserve predicateList(LB1 To UB1 + 1)
        Set predicateList(UB1 + 1) = inputPredicate
    End If

End Sub

Public Sub ClearPredicates()

    If Not predicateList Is Nothing Then Erase predicateList

End Sub

Public Function MatchAny(ByVal leftValue As Variant) As Boolean
    '/ compares leftValue against predicateList. If any return true, then return true, else return false

    CheckInputValue leftValue 

    Dim LB1 As Long, UB1 As Long
    GetBounds LB1, UB1

    Dim matchesAny As Boolean
    matchesAny = False

    Dim predicate As CLS_Comparison_Predicate
    Dim ix As Long
    For ix = LB1 To UB1
        Set predicate = predicateList(ix)
        If predicate.Compare(leftValue) Then
            matchesAny = True
            Exit For
        End If
    Next ix

    MatchAny = matchesAny

End Function

Public Function MatchAll(ByVal leftValue As Variant) As Boolean
    '/ compares leftValue against predicateList. If any return false, then return false, else return true

    CheckInputValue leftValue 

    Dim LB1 As Long, UB1 As Long
    GetBounds LB1, UB1

    Dim matchesAll As Boolean
    matchesAll = True

    Dim predicate As CLS_Comparison_Predicate
    Dim ix As Long
    For ix = LB1 To UB1
        Set predicate = predicateList(ix)
        If Not predicate.Compare(leftValue) Then
            matchesAll = False
            Exit For
        End If
    Next ix

    MatchAll = matchesAll

End Function

Private Sub CheckInputValue(ByVal inputValue As Variant)
    '/ Check for NULL, Objects, Empty and ZLS

    If IsNull(inputValue) Then
        PrintErrorMessage NULL_ERROR_TEXT
        Stop
    End If

    If IsObject(inputValue) Then
        PrintErrorMessage OBJECT_ERROR_TEXT
        Stop
    End If

    If IsEmpty(inputValue) Then
        PrintErrorMessage EMPTY_ERROR_TEXT
        Stop
    End If

    On Error Resume Next
        If Len(inputValue) = 0 Then
            PrintErrorMessage ZLS_ERROR_TEXT
            Stop
        End If
    On Error GoTo 0

End Sub

Private Sub GetBounds(Optional ByRef LB1 As Long, Optional ByVal UB1 As Long)

    LB1 = LBound(predicateList)
    UB1 = UBound(predicateList)

End Sub
\$\endgroup\$
  • \$\begingroup\$ Why the 1 on UB and LB? There's another UB/LB somewhere else? \$\endgroup\$ – Raystafarian May 25 '16 at 14:07
  • \$\begingroup\$ Force of habit. I have LB/UB X where X is the dimension in question throughout all of my code. \$\endgroup\$ – Kaz May 25 '16 at 14:11
2
\$\begingroup\$

I learned something from this

On Error Resume Next
    If Len(inputValue) = 0 Then
        PrintErrorMessage ZLS_ERROR_TEXT
        Stop
    End If
On Error GoTo 0

I learned that On Error GoTo 0 disables error handling in the current procedure. The KB also says:

Without an On Error GoTo 0 statement, an error handler is automatically disabled when a procedure is exited.

So you really don't need it. I also can't figure out under what conditions the len would error. The only thing I could think of is if it's an object, but you've exited by that point. It can't be a negative length can it?

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ And what if, at some later date, me (or somebody else) adds an extra condition after the ZLS check without reading the whole function first? Suddenly On Error Resume Next is still in force, which they did not account for when writing their check. All in all, far safer to just wrap the target check in resume next, goto 0. I also can't think of a condition off the top of my head, but seeing as variant can be any type, it's safer not to assume anything. \$\endgroup\$ – Kaz May 25 '16 at 16:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.