Do we need to create a error handler for each subroutine?
Asked Answered
L

2

5

I copy a piece of code from SO as an example. The subroutine contains an error handler. Should one make an error handler for all Subs?

Public Sub SubA()
  On Error Goto ProcError

  Connection.Open
  Open File for Writing
  SomePreciousResource.GrabIt

ProcExit:  
  Connection.Close
  Connection = Nothing
  Close File
  SomePreciousResource.Release

  Exit Sub

ProcError:  
  MsgBox Err.Description  
  Resume ProcExit
End Sub

And by the way, how does the flow of the control inside a subroutine when the code executor encounter a Exit Sub, End Sub and Resume? And when it encounters a label such as ProcError: during the execution, does it execute it, or does it skip it?

Linear answered 27/5, 2011 at 7:42 Comment(0)
O
10

The short answer is: No, not only do you not need to have an error handler in each procedure, but in fact you would usually not want an error handler in each procedure.

You will want to do the error handling where it makes most sense to do it. Often, you would only want an error handler in the highest-level procedure, i.e. the one that calls all the others; lower-level procedures should kick the problem upstairs and let errors "bubble up" to the higher-level procedure. Sometimes you will want some error handling in lower-level procedures.

For more, I refer you to these two excellent answers by @jtolle:

Also, an internet search will reveal that there is a whole literature on the web about error handling. Some of it is quite wrong, in my opinion! But if it sticks to what I wrote in the first two paragraphs, then it's worth considering.

Exit Sub and End Sub are fairly intuitive: the former stops execution of the current Sub and returns control to the procedure that called it (or stops execution entirely if the procedure was not called by another procedure). The latter is just a indication to the compiler that this where the code for this particular Sub ends -- and if executed, End Sub behaves like Exit Sub.

Resume specifies what should happen next, after an error-handling routine is finished. Plain Resume returns to the same statement that caused the error and tries to execute it again. Resume Next skips the statement that caused the error, and instead goes to the statement immediately following it. Resume mylabel goes to label mylabel:.

If a label such as your ProcError: is encoutered in the course of execution, then nothing special happens, and execution moves on to the next statement after the label. Of course in your example, ProcError: will never get executed directly (i.e. not unless an error is raised) because there's an Exit Sub just before it.


By the way, the ProcExit: block should probably start with an On Error Resume Next (i.e. keep on closing everything and exiting regardless of any errors) or alternatively, as pointed out by @Phydaux, an On Error Goto 0 (on error, stop execution), otherwise if something in there triggers an error, you may get into an infinite ping-pong loop between the error handler and the ProcExit: code.

ProcExit:
   On Error Resume Next ' or, alternatively, On Error Goto 0
   Connection.Close
   Connection = Nothing
   Close File
   SomePreciousResource.Release
Exit Sub
Ous answered 27/5, 2011 at 8:25 Comment(6)
@Jean: +1 for the On Error Resume Next after the Error Handler Label. Made me rethink what I'm doing. But, what if I want the line after the error ocurred get executed? Is it fine to use Resume Next in that case? Hope you get what I'm trying to say (english is not my mother language).Oscilloscope
For the ProcExit: section an On Error GoTo 0 may also be appropriate. But you definitely want one or the other or you're at risk of an infinite loop.Melena
@Oneide: You mean, do the error handling, and then go on to execute the line after the statement causing the error? Yes, in that case, Resume Next should be the last statement of your error handler. To be honest, though, I've never really found a good reason to do this.Request
@Jean: Many thanks. I'll do some tests later, but I think it is pretty clear right now.Oscilloscope
@Phydaux: good point (again). Edited answer to highlight this.Request
I've used Resume Next within an error handler when I was testing for what error was thrown (using Select Case Err.Number), and knew that I wanted to simply ignore certain errors. Never seen a good reason for it to be the catch-all default, though.Thrasher
M
2

Exit Sub will exit the subroutine immediatly like return in Java

End Sub is just the marker for the end of the sub routine block like } in Java

A label is simply a mark in the code wich is used to define a jump destination. In case you did not jump to the label but arrived there "regularly" the label itself will be ignored but the code after the label will be executed as if there was no label, the code in your example will be executed all the way to the Exit Sub statement as long as no error occurs. If one occures it will jump to ProcError

Resume will in this case execute ProcExit see more here

Maleeny answered 27/5, 2011 at 7:49 Comment(2)
You said the label block will be ignore, but how does it recognize the block and seperate it with the rest of the code?Linear
@gunbuster363: I think @cmmi's statement is sort of correct, though not expressed very clearly. What is meant by "the label will be ignored" is this: the label itself doesn't do anything when executed. However, the code after the label (what you call the "label block") will certainly not be ignored and will be executed.Request

© 2022 - 2024 — McMap. All rights reserved.