As we further explore the concept of procedures, there are two distinct but related types of procedures in VB:
While the concept of procedures may seem new, we have used Sub Procedures when we have coded event procedures. We have also used Functions when we used the FormatCurrency and MessageBox functions.
With both Sub Procedures and Functions, there are two closely related but separate components,
The definition is where the code that performs the work of the Sub (or Function) is located. Each procedure will have exactly one defintion. The invocation is where the Sub (or Function) gets used (often referred to as being called). A procedure may be invoked (or called or used) many times within a program. This two part relationship can be viewed graphically by the following diagram:
As mentioned above, the definition, shown on the left, is where the code which performs the task of the procedure is located. The body of the procedure is located between between the procedure beginning and ending statements. The invocation (or call) of the procedure is shown on the right above. When the procedure is used (or called) the statements belonging to the body of the procedure are executed, as if they were located exactly where the invocation is. It is imperative that one understands that both the defintion and the invocation must be present. Without both components, no useful procedure exists.
Once one is ready to implement user defined procedures, they can be coded anywhere within the class, as long as they are not within another procedure. Procedures can have their own local variables and constants, as well as reference variables which have scope broader than local, for example form level. The procedure invocation can be placed in any procedure within the application, depending upon access-method.
[access-modifier] Sub sub-name ([parameter-list]) ' code to be executed goes here End SubThe optional access-modifier determines who can use or call the Sub Procedure, usually using the Public or Private keywords. The sub-name is the name given to the Sub Procedure by the programmer, which should always be a clear, meaningful name. The keywords Sub and End Sub begin and end the procedure. The optional parameter-list is used for getting data into and/or out of the procedure (more below).
Considering the Sub Procedure definition in the diagram above, we see the access-modifier is Private and the sub-name is Display_Header. It should be obvious what this procedure does from the name. The parameter-list is empty, but note the paired (). And finally, the bodyof the sub consists of several Console.WriteLine statements.
The syntax for invoking or calling a Sub Procedure is simply:
[Call] sub-name ([argument-list])Note the optional Call keyword; this may add clarity to the invocation, but is not typically used very often. Note also the optional argument-list; this is directly related to the parameter-list in the Sub defintion. The invocation of the procedure declared above is simply the name given the Sub as follows:
Display_Header () or Call Display_Header()
[access-modifier] Function function-name ([parameter-list]) As return-type ' code to be executed goes here Return return-expression End FunctionAs was the case above, the optional access-modifier determines who can use or call the Function, usually using the keywords Public or Private. The function-name is the name given to the Function by the programmer, and again, should always be a clear, meaningful name. The keywords Function and End Function begin and end the function. The optional parameter-list is used for getting data into and/or out of the function (more below). The return-type is the data type of the value the function is going to return. What is this you ask? Recall that by definition, a function must return at least one value. The return-type is the data type of the value returned by the function. Functions use the keyword Return followed by the return-expression, which is evaluated to the value the function will return. The expression can be a constant, a variable, a mathmetical expression, or any other valid expression, as long as it is consistent with the return-type. Notice also the location of the Return statement; in general, each function should have a single Return statement located as the last statement prior to the End Function statement.
The syntax for invoking or calling a Function is a bit different, due to the return value. A function is typically called as follows:
variable = function-name ([argument-list])Note the use of the equal sign above; this is the assignment operator, that is how a function returns a value and assigns it to a variable. What type must the variable be? You should answer quickly that the data type for the variable must be the same as the return-type of the function (unless a conversion method is to be used).
Looking at an example of a function which will return the larger of two Integer values, we get something like:
Dim intOne As Integer ' note these are form level variables Dim intTwo As Integer Dim intBig As Integer Public Function LargerValue () As Integer Dim intReturnValue As Integer If intOne > intTwo Then intReturnValue = intOne Else intReturnValue = intTwo End If Return intReturnValue End FunctionThis function can then be invoked as follows:
intBig = LargerValue ()Note that functions can also be invoked "in-line", where the result of the function is returned to the position of the invocation, rather than being assigned to a variable. This could be done as follows:
txtOutput.Text = Convert.ToString (LargerValue ())Here, the result of the LargerValue function is returned to the position between the outer parentheses, which is then converted to a string and assigned to a TextBox object.
Here, data stored in the Text property of a TextBox object is being passed into the ConvertTo procedure, so that it may be converted to a decimal type and the returned result assigned to the decimal variable.
When passing data to and from user defined procedures and functions, the procedure invocation and the definition both need to be looked at closely. Data passed to or from a procedure is done so via the argument list in the procedure invocation. This data is associated with the corresponding parameter list in the procedure definition. That is, each argument in the invocation is associated, or passed to a corresponding parameter in the definition, represented in general as follows:
In the above example, 3 arguments are present in the argument list in the procedure invocation, which correspond to (or are being passed to) 3 parameters in the procedure definition. In general, you will want to closely follow these rules regarding parameter passing:
Sub EvenOdd (intNum As Integer) If (intNum Mod 2) = 0 Then MessageBox.Show (intNum.ToString & " is even!") Else MessageBox.Show (intNum.ToString & " is odd!") End If End SubThis Sub Procedure could then be called as follows:
EvenOdd (6) ' or Call EvenOdd (6) EvenOdd (6 + 11) EvenOdd (intAge) ' assuming intAge was declared as an IntegerWe could also write the above using a Function procedure, which returns a Boolean value to indicate whether the input is even or odd. If we change the name a bit to reflect the new functionality, we get something like:
Function IsOdd (intNum As Integer) As Boolean Dim blnResult As Boolean If (intNum Mod 2) = 0 Then blnResult = False Else blnResult = True End If Return blnResult End SubThis could then be called as follows:
blnOdd = IsOdd (6) ' assuming blnOdd was declared as a Boolean blnOdd = IsOdd (6 + 11) If IsOdd (intAge) Then ' assuming intAge was declared as an IntegerIt is time to introduce the final piece to understand parameter passing, namely parameter passing mechanisms. Sometimes data is passed into a procedure to be used within the procedure. Sometimes data is passed out of a procedure (i.e. a value is returned). And sometimes data is passed both into and out of a procedure. A general example of this directional parameter passing follows:
Sub CalculateTax (decAmount As Decimal, decTaxRate As Decimal, decTax As Decimal) decTax = decAmount * decTaxRate End SubHopefully it is somewhat obvious that the first two parameters are required to be passed into this procedure to be used in the calculation of the tax value, which then needs to be passed out (or returned). Why, you ask? Without the first two values being passed in, we could not compute the value of the tax.
Thus when passing data (only) into a procedure, we would not expect that data to change, or to be allowed to change. For example, in the Sub procedure above, you would not want the decAmount or the decTaxRate values to change, since they were set prior to the invocation. Visual Basic provides a mechanism to control whether data going into a procedure may be changed upon returning from the procedure. The two techniques to manage this are passing by value and passing by reference.
Passing by value prevents any changes made to data values within the sub procedure from returning from the procedure (i.e. at the calling location). Conversely, passing by reference allows changes made to data values within the procedure to return from the procedure. Both techniques use keywords which must be specified in the parameter list, unless one wants to use the default. The default type is by value, since it is the "safest" method. It is important to note that each individual parameter can be passed either way, depending upon whether its value should be changed. Only values which must change upon return should be passed by reference.
Passing by value can be summarized as follows:
Passing by reference can be summarized as follows:
Sub CalculateTax (decAmount As Decimal, ByVal decTaxRate As Decimal, ByRef decTax As Decimal)It should be understood that the first parameter is passed by value since neither keyword is present, therefore the default technique applies. The second value is passed by value, since this is explictly stated. And the third parameter must be passed by reference, since its value is computed within the procedure and must be returned.
Note that passing ByVal does not prevent the variable from being changed in the procedure, it just prevents any changes from returning from the procedure. One way to think about this is the data values can go in only, any changes will never come out, as pictured here:
In contrast, passing ByRef allows any changes to variables to be returned to the calling location. One way to think about this is the data values can go in as well as out, as pictured below:
Use a Function if:
Note that Functions and Sub Procedures can be written to have exact fucntional equality.
Next Section: Scope | Table of Contents |
©2007, Mark A. Thomas. All Rights Reserved.