Pattern to handle expected errors locally, rethrow unexpected errors Pattern to handle expected errors locally, rethrow unexpected errors vba vba

Pattern to handle expected errors locally, rethrow unexpected errors


I made a user-defined type that has the same members as the Err object (Number, Source, Description, etc.). The SaveErr function will basically copy the values of the Err object properties into a variable of this type, and RaiseSavedErr will raise an error using those property values.

Of course the exact same thing could be done using a class and methods instead of a user-defined type and functions/subs. But the idea would be the same.

Example:

    On Error Resume Next    personIndex = FindInArray(personName, personArray)    savedErr = SaveErr(Err) 'Save values of Number, Source, Description, etc.    On Error GoTo ErrorHandler    'Segregate error handling strategies here using savedErr    If savedErr.Number = ERR__ELEMENT_NOT_FOUND_IN_ARRAY Then        MsgBox "Name not found in person array. Using default person."    Else        RaiseSavedErr savedErr 'rethrows the error    End If

I'd like to know if there is a more standard or elegant way of doing this.


This answer is my opinion on the problem at hand, perhaps viewed from a slightly different angle.

When considering this block of code:

On Error Resume NextpersonIndex = FindInArray(personName, personArray)If Err.Number = ERR__ELEMENT_NOT_FOUND_IN_ARRAY Then    MsgBox "Name not found in person array. Using default person."ElseEnd If

You mention: "expected errors" in the title.
But the thing is that no error should be thrown if you know in advance that it may occur.
They are a form of validation that should in my opinion be built in into the functions in the form of conditional statements.

The before mentioned code block would be something like this on a basic level:

    If Not (in_array(vArray, "Jean-Francois")) Then        MsgBox "Name not found in person array. Using default person."    End If

Which in my opinion is a lot cleaner and readable.
With a custom function that is not part of the base code, but that does your check behind the scenes. Reusable functions can be wrapped in a module that you use in a way that is very similar to a static class.

Public Function in_array(vArray As Variant, sItem As String) As Boolean    Dim lCnt As Long    in_array = False    Do Until lCnt = UBound(vArray) + 1        If StrComp(vArray(lCnt), sItem, CompareMethod.Text) = 0 Then            in_array = True            Exit Function        End If        lCnt = lCnt + 1    LoopEnd Function

Even better would be to use the in_array() function from within the findInArray() function and have only 1 line of code in the basesub, which would be:

personIndex = FindInArray(personName, personArray)

Let the functions in the back handle the rest and intercept exceptions that you can foresee.
This is only an example, obviously you write the functions and return values that are useful for you and you could probably add more extensive validation.

My point is that these return values are return messages that are a part of the application / validation logic, I don't see them as technical errors - hence, I don't see any benefit in using an error handler for them as a custom created function exactly fits your needs in a (my opinion) much cleaner structure.

I consider it a technical error when you pass for example three arguments into the function call while it only accepts two. The error handler notifies you, after which the developer may decide to make the current function more dynamic by allowing eg. optional parameters and fixing the bug.


Though I am a bit confused by the question asked (and I've read it over quite a lot of times by now :-)), I have a very strong feeling that the source of this dilemma lies within function scopes.
If it's ok, I will use some basic examples that show a pattern but are not 1-1 on par with your code.

How do I segregate the expected errors I want to deal with locally, from unexpected errors to be dealt with in error handling routine (or elsewhere)?

I kind of feel that the answer lies within the question itself.
Error handlers are functional within the local scope of sub routines / function that you call from a lower level sub routine or function.

I find that if I deal with some expected error numbers locally, I can't easily "rethrow" unexpected error numbers to be dealt with elsewhere.

You can if you delegate the code that you want to check for local errors to external functions / sub routines that you place on top of a certain level in the call stack. Since they handle errors within their own scope, they won't mix up with each other.

Consider this code:

Sub baseSub()    Dim n As Integer    n = checkDivision(1, 0)          n = 1 / 0  ' cause an errorEnd SubPublic Function checkDivision(iNumerator As Integer, iDenominator As Integer)    On Error Resume Next    checkDivision = iNumerator / iDenominator    If Err.Number <> 0 Then        checkDivision = Err.Number        Exit Function    End IfEnd Function

On the contrary: when applying On Error Resume Next from a baseSub, all functions that are placed on top of the call stack will ignore the errors as well. But, it doesn't work the other way around.

I think you may use this to your advantage.

So to conclude, I believe that you can solve the problem by trapping the expected errors in the delegated functions that you place on higher levels of the call stack.

If this doesn't work, then I'm out of ideas.