Visual Basic/Functions and Subroutines
This lesson will instruct you on the creation and usage of functions and subroutines using Visual Basic 6.0. This lesson assumes that you can navigate the Visual Basic IDE, and create a simple project with which to test code. It is recommended that you read the Introduction to VB6 as well as the Variables and Types in VB6 lesson before starting.
What Are Subroutines?
Subroutines can be thought of as miniature programs. A subroutine has a name attributed with it, much like a variable does. Unlike a variable, a subroutine doesn't hold data. Instead, it holds code. When the code in a subroutine is executed, the subroutine is said to be "called". Therefore, one subroutine can "call" another subroutine. Some subroutines are called automatically when certain actions are performed. For example, the Form_Load subroutine is automatically called when a form loads. This is where you have been inserting your test code before. What you were actually doing was adding code to this subroutine.
Why Use Subroutines?
You may ask yourself why subroutines would even be used. Why wouldn't you simply put all of your code in one place? Subroutines are useful because they eliminate redundancy. Consider a complicated program like a word processor. When certain actions are performed, such as closing the program, opening a file, or closing an individual file, the word processor would probably check to see if you had modified your document. If the user had modified the document since they opened it, the user would be prompted to save the file before performing the action. You could imagine that checking if the document was modified, prompting the user, and acting on the input would require many lines of code. If the programmer had literally typed this code into all of the places in the program where this check was to be made, it would still work fine. However, what would happen if the way the program handles documents changed, and therefore this code needed to be changed? The programmer would have to change the code in every place where this check was made. Even worse, what if the programmer changed the code in a few places but not in another? This would lead to bugs that are difficult to track down. Instead, if this code was put in a subroutine, the subroutine would simply be called from all of these places. If the code then needed to be changed, the programmer would only have to change it in one place; inside the subroutine. By doing this, subroutines eliminate redundant code, making the entire program easier to manage.
Creating A Subroutine
Creating a subroutine involves two lines of code. Luckily though, the Visual Basic code editor is smart, and will insert the second line for you! A subroutine begins with the word "Sub", followed by a space, then a name identifying the subroutine. Two parentheses follow, which are used for a parameter list. Don't worry about these yet, they will be covered later in the lesson.
Sub TestSub() End Sub
After you enter the first line and press Enter, the second line will automatically be added for you. These lines represent the start and end of the subroutine. Any code inserted between these lines will be executed when the subroutine is called. A subroutine can be called in one of two ways: using the Call keyword, or by simply stating its name.
Sub TestSub() MsgBox "Code in TestSub()" End Sub Private Sub Form_Load() MsgBox "Code in Form_Load()" TestSub MsgBox "Back in Form_Load()" End Sub
You can also use the Call keyword, as mentioned above:
Sub TestSub() MsgBox "Code in TestSub()" End Sub Private Sub Form_Load() MsgBox "Code in Form_Load()" 'This line is functionally equal as the line in the previous example Call TestSub MsgBox "Back in Form_Load()" End Sub
The previous listing introduced a new syntax element: the comment. A comment is a line that is NOT source code. Instead, it is there as guidance to the person reading the code. When programmers write programs, they usually (or at least they should) add comments describing large sections of code that could potentially be confusing. Comments begin with an apostrophe (" ' ") and end with a new line. Everything that you type after the apostrophe is ignored by Visual Basic, which is the entire point of comments. You will see comments in all future listings describing new concepts and syntax.
The declaration of a subroutine has an optional keyword that can be used before "Sub". You may enter a keyword representing scope here. "Private" and "Public" are examples of scopes. You may have noticed that the Form_Load subroutine has the word "Private" before "Sub". This declares that this subroutine has a Private scope. If you don't specify the scope of a subroutine, Visual Basic will use a default scope. You should never rely on default scope, however. Get in the habit of always explicitly declaring the scope of your subroutines.
What Is Scope?
In the context of subroutines, scope represents where in your program the subroutine can be called from. Subroutines with a Private scope can only be called from the source file from where they were defined. Subroutines with a Public scope can be called from anywhere in your program. For example, a subroutine with a Private scope in a form can not be called from another form, whereas it can if it has a Public scope.
Why Use Scope?
Why would you ever limit where you can call a subroutine from? Why wouldn't you make all subroutines Public so that there are no limitations on your program? Subroutine Scope is one of many tools that programmers can use to find bugs. If you know that your subroutine should never be called from a different source file, you should declare the subroutine to be Private. This will prevent you from making a silly mistake and calling this subroutine where it shouldn't be called. This will prevent mistakes that could be extremely damaging and hard to detect. Instead, your program will crash with an error rather than executing the subroutine with unpredictable results.
Parameters, also called Arguments, are variables that can be "passed into" a subroutine. A subroutine with parameters looks like this:
Private Sub DisplayAdd(x As Integer, y As Integer) MsgBox x + y End Sub Private Sub Form_Load() DisplayAdd 5, 2 End Sub
A new subroutine has been declared called DisplayAdd. This declaration is different than the declarations that you have seen so far, however, as code has been added between the parenthesis. From your knowledge of variables, this syntax should look somewhat similar to you. x As Integer and y As Integer appear to be variable declarations without the "Dim" keyword. These declarations are separated by a comma. These variables are the Parameters for the DisplayAdd subroutine. Code within the subroutine can access x and y as usual, as if they were normal variables. However, when the subroutine is called, the calling subroutine will also provide values for these parameters. Therefore, the subroutine has now become dynamic. The code can act on input without caring where the input came from. When the Form_Load subroutine calls DisplayAdd with the parameters 5 and 2, the code within DisplayAdd is executed. The first line adds x and y together and displays the result. x and y have already been filled with the values 5 and 2 from the Form_Load subroutine. The calling subroutine doesn't have to use numeric constants, however. It can use variables as well:
Private Sub DisplayAdd(x As Integer, y As Integer) MsgBox x + y End Sub Private Sub Form_Load() Dim a As Integer Dim b As Integer a = 5 b = 2 DisplayAdd a, b End Sub
This code has identical results. Note that DisplayAdd cannot access a and b. As far as DisplayAdd is concerned, a and b are represented as x and y. Attempting to access a or b from DisplayAdd would result in an error.
ByRef and ByVal
Parameters can be sent to a subroutine By Reference (ByRef) or By Value (ByVal). ByRef is the default, and means that changes to the variable in the subroutine will result in changes to the source variable outside of the subroutine. ByVal literally copies the values of the variables from the calling subroutine into the called subroutine. By doing this, the variables can be changed, but their values will not change outside of the called subroutine. ByVal can also be a lot slower with large variable types, however, since memory has to be copied from one location to another. If you don't have any reason to do so, there is no need to pass variables ByVal. You can explicitly state the way that a variable is passed to a subroutine by using these keywords before the variable name. Using the ByRef keyword, one could write a Swap function, which switches the values of 2 variables.
Private Sub Swap(ByRef x As Integer, ByRef y As Integer) Dim temp As Integer temp = x x = y y = temp End Sub Private Sub DisplayVals(ByRef a As Integer, ByVal b As Integer) 'Don't worry about understanding the next line yet, it will be explained later MsgBox "a = " & CStr(a) & vbCrLf & "b = " & CStr(b) End Sub Private Sub Form_Load() Dim a As Integer Dim b As Integer a = 10 b = 12 'Display values, swap, and display again DisplayVals a, b 'The next line is functionally identical to "Swap a, b" Call Swap(a, b) DisplayVals a, b End Sub
Notice that Call was used instead of simply stating the subroutine name. When using the Call method however, you must use parenthesis when calling the subroutine. Note that this program would also have worked without typing "ByRef" anywhere, since it is the default. The ByRef and ByVal keywords are rarely used in simple programs, however, but it's a nice trick for your toolkit.
Subroutines have a close cousin called Functions. Functions are basically the exact same as subroutines, except that they return a value. That means that the function itself has a type, and the function will return a value to the calling subroutine based on the code that it contains. An example of this would be a function that adds two numbers, shown below. A function is declared the exact same way as a subroutine, except using the "Function" keyword instead of "Sub". To return a value, assign a value of the proper type to the function's name, as if it were a variable.
Private Function Add(ByVal x As Integer, ByVal y As Integer) As Integer Dim Res as integer Res = x + y Add = Res End Function Private Sub Form_Load() Dim a As Integer Dim b As Integer Dim c As Integer a = 32 b = 64 c = Add(a, b) MsgBox ("Sum is : " & c) End Sub
Functions Or Subroutines?
The best way to determine which is better for your application is by asking yourself a simple question. Will you need to return a value? If so, use Functions. If you don't, use subroutines.
|Learning Visual Basic|
|Previous: Visual Basic/Control Structures and Logical Expressions — Next: Visual Basic/Basic Graphical User Interfaces|