Procedures


Introduction

In general, a procedure is a self-contained, independent grouping of code, within a larger program designed to perform a very specific task. Procedures within a program may not necessarily be related to each other, other than to help accomplish the overall task of the application itself. Procedures allow for what is known as modular programming, that is dividing programs into smaller pieces (i.e. modules). Modules in VB are typically referred to as procedures. Why modular programming? Modular programming allows for:

As we further explore the concept of procedures, there are two distinct but related types of procedures in VB:

  1. Sub Procedures

  2. Function Procedures

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,

  1. the Sub (or Function) definition

  2. the Sub (or Function) invocation

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.


Sub Procedures

As mentioned above, Sub Procedures are one of the two general types of procedures in VB. Sub Procedures differ from Functions in the fact that Sub Procedures may return zero or more values, where Functions must return at least one value (more on this in Functions below). The general syntax for a Sub Procedure definition is as follows:
	[access-modifier] Sub sub-name ([parameter-list]) 

	    ' code to be executed goes here

	End Sub
The 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()

Function Procedures

Functions are the other general types of procedures in VB. As mentioned, functions must return at least one value. Thus, the general syntax for a Function definition differs a bit from Sub Procedures and looks as follows:
	[access-modifier] Function function-name ([parameter-list]) As return-type
	    
	    ' code to be executed goes here

	    Return return-expression

	End Function
As 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 Function
This 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.


Passing Data to Procedures

As was mentioned in the introductory paragraph above, one of the strengths of modular programming is the ability to securely share data between procedures. Securely means that a procedure may have access to data as the programmer sees fit, and may or may not have the ability to alter that data. Formally, this is referred to as parameter passing mechanisms (or techniques). You have already experienced passing data into a proceure, however, you most likely did not know it. You passed data into a procedure when you used the FormatCurrency function as well as when you used the CovertTo methods, as in the diagram below:

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:

One important thing to understand from the above example is that arguments must be declared before being passed into procedures. Parameters on the other hand, get instantiated as the procedure is entered, thus the parameters will need to be declared in the definition of the procedure. This is why each parameter in the parameter list above is followed by an "As type" statement. Consider the following Sub Procedure which accepts one parameter of type Integer, and reports if the parameter is an even or an odd number, we get a definition as follows:

	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 Sub
This 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 Integer
We 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 Sub
This 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 Integer
It 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 Sub
Hopefully 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:

We should now understand that the CalculateTax procedure above will not actually work as desired. To make this work correctly, the above definition must actually look 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:


Functions vs. Sub Procedures

Students often ask "when creating a procedure, should I use a Function or a Sub Procedure?" The answer to this is fairly straightforword, sort of. Some general guidelines are:

Use a Function if:

Use a Sub Procedure 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.