I just moved over to the Visual Basic team here at work.
What is the equivalent keyword to break in Visual Basic, that is, to exit a loop early but not the method?
In both Visual Basic 6.0 and VB.NET you would use:
Exit For to break from For loop
Wend to break from While loop
Exit Do to break from Do loop
depending on the loop type. See Exit Statements for more details.
In case you're inside a Sub of Function and you want to exit it, you can use :
Exit Sub
or
Exit Function
Exit [construct], and intelisense will tell you which one(s) are valid in a particular place.
Related
I want to end a main sub from another sub.
Here is an example code to illustrate what I need to do:
Sub main()
endMainSub()
'do other stuff
End Sub
Sub endMainSub()
**'here I need a code to end main Sub**
End Sub
From endMainSub, I would like to terminate main sub before "do other stuff".
I need something like "End" in VBA.
End exists in VB.NET too, so you could use it. You should NEVER do so though. End simply stops executing the application at that point, with no regard for what state it might be in. It's like closing applications by using End Task in Task Manager, which I hope you use only as a last resort.
As suggested, you should be returning a result from the second method that indicates that the application should exit and the first method should explicitly choose to exit or not based on that, e.g.
Sub Main()
If EndMainSub() Then
Return
End If
'...
End Sub
Function EndMainSub() As Boolean
Dim result As Boolean
'Some work that sets result here.
Return result
End Function
I think you should use
Application.Exit
It's more object orientated and allows to execute all closing and disposing events. "End" still exists, but it will end immediately and no clean up routines will be executed.
I would like to know if there is an equivalent of Python's pass statement in VBA.
I am using Excel 2016.
The use of Stop (see this answer) seems to be the best thing to do if you are looking for some "non-statement" that you can use to insert a breakpoint, because the Stop command causes the code to break when it is reached, i.e. you don't even need to mark it as a breakpoint because it is one.
You might also like to consider using Debug.Assert some_logical_expression, which will break automatically whenever the logical expression evaluates to False. So Debug.Assert False would be equivalent to Stop, and Debug.Assert x = 3 would be equivalent to If x <> 3 Then Stop.
In Python you need the Pass, because otherwise the methods will not run.
In VBA, its perfectly ok if you leave an empty method like this:
Public Function Foo() As String()
End Function
Maby you are looking for the "Stop" statement.
The good thing about it is that it doesn't clear your variables.
It depends what are you trying to achieve.
You may declare a Label and then use GoTo Label e.g. declare a label (like Skip:)in your code where you want to jump if a condition is met and then use GoTo Skip
Below is the small demo code to give you an idea about this...
Dim i As Long
For i = 1 To 10
If i = 5 Then GoTo Skip
MsgBox i
Next i
Skip:
I am dealing with a good amount of workbooks with many procedures. The deeper I go in my project, the more I try to write functions or sub to process common tasks.
First of all, as the final user will be an average Excel user, I decided to protect and centralize all my code in a personal macro workbook. It sounds to me a good idea, but maybe some of you, Excel gurus, don't agree.
Then I wrote a Public Sub ErrorHandler () to deal with errors in all my procédures. I am fully aware of the Error Bubble Up. My procedure will be soemthing like this:
' All déclarations are outside
Public Sub ErrorHandler ()
Lg1 = Err.Number ' Lg1 is Long
Select Case Lg1
Case 1004
MsgBox ("File is not fund. Please verify its path.")
Exit Sub '!EDITED! <GoTo NextCode:> is much better indeed
' ...more code with other errors...
End Select
NextCode: ' !EDITED!
' ...some cleaning and initialize variables to nothing or 0
Lg1 = 0
Err.Clear
End Sub
Then I would like to use this sub in other sub this way :
On Error Go To MyError: ' <On Error call ErrorHandler> is not permited
'...more code....
MyError:
call ErrorHandler
Now a few questions:
Is it a good practice ? If not, what would you recommend ?
In case 1004 for example, when I say Exit sub, will the ErrorHandler sub itself go to end and do the cleaning stuff, or will it stop too ?
Any good hints about common and useful user defined errors (513-65535) ?
Thank you for help.
When you do "Exit Sub" in the ErrorHandler(), it will of course leave the ErrorHandler() immidiately and return to the caller, so no cleanup is done. You can of course remove the "Exit Sub", so your cleanup will run, but it will always be the same for all cases.
The Problem I see in this approach comes after returning from ErrorHandler(). You return to the caller with absolutely no idea what ErrorHandler() did. How are you going to continue from there? Catching and Displaying the Error is only half the solution. You need to come up with a way to continue from there. If it's a "common Task" you are in, you need to cancel/abort/resume that in some way or at least return some error code to it, so it knows to end gracefully.
VBA itself is a bit bad at this situation. We use http://www.everythingaccess.com/vbwatchdog.htm in our projects to handle this problem as it provides a powerful generic error handling method, quite as you aim to do.
This is probably the dumbest question I've ever asked here, but it's hard to find answers to things like this.
I have a program with a bunch of modules/subs that each calculate a different variable. They're pretty complex, so I like to keep them separate. Now I want an earlier module to skip to another module based on user input. I thought I could use the call (sub name) method for this, but then the program returns to where the call line was and continues on that module from where it left off.
Example:
Module 1:
Sub NewPracticeSub()
Call otherpracticesub
MsgBox ("We've gone back to this sub... :(")
End Sub
Module 2:
Sub otherpracticesub()
MsgBox ("We're in the other practice sub!")
End Sub
I don't want it to return to Module 1. What can I do to have it switch control to Module 2 without it then returning to complete Module 1 upon completion of Module 2?
I feel like I just used the most confusing language possible to explain all of this, but thank you for your help anyways!!
Edit: I know I used the words module and sub interchangeably, and I know they're different. I like to keep each sub (which are each very large in my program) in their own modules because it's easier to keep track of them, and easier to explain/demonstrate the application flow to other people.
I think all you're looking for is the command Exit Sub which will make the program leave the subroutine without continuing any further, But the way you usually want to do this is, rather than calling a Sub, rather call a Function that returns a boolean value.
So, for example:
Public Function MyFunc() as Boolean
....
If [good] MyFunc = True
Else MyFunc = False
End Function
Then you could do something along the lines of:
Sub MyCallingSub()
...
If MyFunc = True then Exit Sub
Else ...
End Sub
It just adds in A LOT more felxibility and ability to choose whether you want to continue further in your sub or not.
Hope that makes sense.
Other than using the ugly End statement which I will describe below (and strongly recommend you to avoid), I'm not aware of any way to circumvent the call stack. Even John's response necessarily returns to the calling procedure, and evaluates another statement to determine whether to proceed or end.
This may yield undesirable outcomes, which is why I hesitate to recommend it, in favor of properly structuring your code, loops, etc., with respect to the call stack.
In any case, here is how you can use the End statement within your child subroutines, without needing any sort of public/global variables. This still allows you the flexibility to decide when & where to invoke the End statement, so it need not always be invoked.
Sub NewPracticeSub()
Call otherpracticesub, True
MsgBox ("We've gone back to this sub... :(")
End Sub
Sub otherpracticesub(Optional endAll as Boolean=False)
MsgBox ("We're in the other practice sub!")
If endAll then End '## Only invoke End when True is passed to this subroutine
End Sub
Why I say this method should be avoided, via MSDN:
"Note The End statement stops code execution abruptly, without
invoking the Unload, QueryUnload, or Terminate event, or any other
Visual Basic code. Code you have placed in the Unload, QueryUnload,
and Terminate events of forms and class modules is not executed.
Objects created from class modules are destroyed, files opened using
the Open statement are closed, and memory used by your program is
freed. Object references held by other programs are invalidated.
The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs
holding references to objects created from your public class modules
and no code executing."
It will always return but that doesn't mean its a problem. I suggest you use Exit Sub as follows:
Sub NewPracticeSub()
Call otherpracticesub
**Exit Sub**
'Nothing more can execute here so its no longer a worry
End Sub
Module 2:
Sub otherpracticesub()
MsgBox ("We're in the other practice sub!")
End Sub
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?
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:
VBA Error "Bubble Up"
Handling errors in math functions
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
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