Sub and Function Procedures

Sub and Function Procedures

Sub and Function procedures are workhorses for encapsulating classic Visual Basic code. Although a few new rules about their use exist in the .NET version of Visual Basic, many syntax conventions are exactly the same. This section discusses the important issues of using these two types of procedures. In addition, the section highlights new topics for each procedure type so that you can take advantage of them as appropriate.

Creating Reusable Code Blocks

Classic Visual Basic developers have benefited from the ability to create code blocks that collectively comprise an application. This ability to compartmentalize code and reuse it anticipated the power of object-oriented programming. A code block in a Sub procedure or a Function procedure performs a set of instructions. You can pass values into either of these two types of Sub procedures. The Function procedure provides a built-in mechanism for returning an object, such as the outcome of a computation. By calling these procedures at different points from another procedure, you are essentially reusing the code in the procedures.

A Sub procedure can perform a task. You can vary the operation of the task performed by the parameters that you pass to the Sub procedure. For example, a Sub procedure can compute the product of two numbers and display the result. If the two numbers happen to be the same, the product denotes the area of a square. If the two numbers are different, the product can represent the area of a rectangle. By internally checking the values of passed parameters, the Sub procedure can indicate whether the product represents the area of a square or a rectangle.

Passing Values

Sub procedures in Visual Basic .NET work similarly to Sub procedures in classic Visual Basic. However, in this section, we will discuss a couple of enhancements to .NET Sub procedures.

You likely will notice the ByValue and ByRef keywords before passed arguments. By default, classic Visual Basic passes arguments to procedures by reference. When a Sub procedure accepts an argument this way, the Sub procedure can update the original value in the calling procedure. This feature introduces a potential source of error ”or, at the very least, lack of isolation ” between the code blocks in a solution. With Visual Basic .NET, the default technique to pass an argument is by using the ByVal keyword. The ByVal keyword specifies the acceptance of a copy of the argument value from the calling procedure. This enables the Sub procedure to manipulate the value of a passed argument without updating the corresponding argument value in the calling procedure. If you want your Sub procedure to recompute one or more values in its calling procedure, use the ByRef keyword before those arguments in the Sub statement.

The sample presented at the end of the preceding section demonstrates the syntax for calling Sub procedures with and without passing arguments. The main procedure called two Sub procedures ” democlass and demostructure . The editor in Visual Studio .NET automatically inserts the closing parentheses, which are mandatory even when a Sub procedure requires no arguments. The New procedure in the NameClass class illustrates the syntax for the ByVal keyword. To accept values by reference instead of by value, replace each ByVal keyword in the Sub statement with the ByRef . The democlass procedure demonstrates the syntax for invoking the New method implemented by the Sub procedure with that name in the NameClass class. Although the ByVal keyword prohibits updating the p1 and p2 members by using the New method, the declaration of these members enables updating with a simple assignment statement. Dim statements for variables implicitly denote a Public access modifier. (We will discuss using access modifiers a bit later in the section.)

Function procedures are designed to pass back a value. In fact, a Function procedure will frequently appear in an expression in the calling procedure so that it supplies a value for the computation of a result. By using an As keyword in the Function procedure declaration, you can specify the data type for the returned object from the function. Although you can return a value by setting the function name equal to the value, a new Return keyword offers an alternative means of designating a function s return value.

The following main procedure invokes a Function procedure named MySquare . The script is available in the materials posted for this chapter as MySquarer.txt; you can copy the script into an empty project shell to test its performance. The Function procedure takes a single argument by value and returns the square of the input argument. The Function procedure contains a single line of code that illustrates the syntax for the Return keyword. Both the input and output from the Function procedure have a Double data type.

The main procedure performs three steps. First, it collects the number to square. An InputBox function gets the input as a string, and a CDbl function converts the string to a Double data type, which a Dim statement stores in MyNumb . Second, the main procedure computes a string for display in a message box function. The expression for computing the string invokes the MySquare procedure to compute the square of the value collected in the first step. The second step explicitly converts the return value to a string for its use in the string expression. The final step invokes the MsgBox function to display the string computed in the second step. This last step shows the result evaluated by the MySquare procedure.

 Sub main() 'Get input. Dim MyNumb As Double = _ CDbl(InputBox("Enter a number", "Number to square")) 'Compute output. Dim str1 As String = "The square of " & MyNumb.ToString & _ " is " & CStr(MySquare(MyNumb)) & "." 'Display result. MsgBox(str1, MsgBoxStyle.Information, "Your result") End Sub Function MySquare(ByVal MyNumb As Double) As Double 'Compute and return value for function. Return (MyNumb ^ 2) End Function 

Using Option Strict

The Option Strict statement is a statement introduced with Visual Basic .NET. As with the Option Explicit statement available with classic Visual Basic, you must specify this directive as the first line of any code module. You can turn the Option Strict on or off by following the statement with the On or Off keyword. This statement is turned off by default.

Although you can still use Option Explicit to require the explicit declaration of variable data types, the new Option Strict directive implies Option Explicit . In addition, the Option Strict directive governs how you can specify the input and output values from procedures. In the preceding MySquare procedure, the input argument ( MyNumb ) and the output argument (the function name) have data type assignments via the As keyword. Without the Option Strict On directive at the top of a code module, you can remove either or both As clauses and the project will still compile properly. But once you designate the Option Strict On directive, the project will not compile without both As clauses. The use of the Option Explicit directive does not result in sensitivity to explicit type declarations for input and output arguments for procedures.

More generally , the Option Strict On directive allows only widening data type conversions ”conversions that will surely succeed. For example, you can always convert a variable declared as a Byte data type to an Integer data type. This is a widening conversion because no data loss can occur. On the other hand, transforming a variable declared as an Integer type to another variable declared as a Byte data type is a narrowing conversion. Because the Integer data type range extends well above and below the range of legitimate values for a Byte data type, it is possible ”but not necessary ”for the conversion of the Integer data type to the Byte data type to throw a run-time error, which is known in the .NET Framework as an Exception object. (See Chapter 4 for more details on run-time error processing and Exception objects.)

Using Access Modifiers

Access modifiers control access to entities within class and structure instances. You can use access modifier keywords when declaring entities such as variables and procedures within classes and structures. Understanding access modifiers will reinforce your understanding of Visual Basic .NET types and how you can use those types. This section briefly summarizes selected access modifier keywords to help you determine which access modifiers to use in various contexts.

Table 3-3 includes a summary of the most common access modifiers. Even if you do not specify an access modifier when declaring an entity, the .NET Framework will infer some level of accessibility for an entity. For example, the default level of accessibility for a class is Public . Even if you declare a class as having Public access, its members can have narrower access, such as Private access. In fact, this specific use of access modifiers is typical. You often will want to define local variables within a class that are accessible only from the same class. This practice allows you to tightly restrict access to selected class members.

Table 3-3: Access Modifiers for Procedures and Variables

Access Modifier

Description

Public

Provides unrestricted access to an entity.

Protected

Provides access within a class or any derived classes based on a class.

Friend

Limits access to other elements within an assembly.

Protected Friend

Permits accessibility by union of Protected and Friend so that access is possible from within the same assembly and derived classes. The combination of these terms applies exclusively to class members.

Private

Enables access only from within a declaration context, such as a class, enumeration, or procedure.

Shared

Specifies access exclusively for members of a class or a structure. Shared members are available without instantiating an instance of a class.

Static

No longer applies to procedures but is still available for use with individual variables. Static variables retain their values between calls to a procedure.

A couple of modifier keywords in Table 3-3 apply to special situations. The Static keyword maintains variable values between calls to a procedure. In contrast to its use in classic Visual Basic, the Static keyword does not apply to Sub and Function procedures. With Visual Basic .NET, you must apply the Static keyword to the variables within a procedure to which it applies. The Shared keyword is another special member modifier. Members declared with Shared are not associated with any particular instance of a class. You can reference shared members even without creating an instance of a class, and shared members such as properties will have the same value across all instances of a class. If you change a Shared variable in one instance, all instances will have access to the revised value.

Optional Parameters and Parameter Arrays

One of the best ways to make procedures reusable is to make them flexible. Two argument declaration techniques facilitate this goal. The first allows you to designate an optional argument for a procedure. The second allows you to specify a parameter array containing an indefinite number of items. This section will present two samples that demonstrate how to put these techniques to work in an application.

Optional Parameters

The Optional keyword in Visual Basic .NET works similarly but not identically to the way it worked in classic Visual Basic. Use Optional as the first keyword for any argument declaration that specifies an optional argument. After designating any argument in the list for a procedure as optional, all subsequent arguments for a procedure must be optional. Nevertheless, you must mark each subsequent argument with the Optional keyword. Visual Basic .NET adds the requirement that you must designate a default value for an argument to which you apply the Optional keyword. With classic Visual Basic, the designation of a default value was not mandatory. You specify the default value for an argument by trailing its declaration with an equal sign (=) and the value to assign to the argument if the calling procedure does not specify a value for the optional argument.

The following code builds on the earlier sample that computed the square for a number. (The text for the earlier sample is available as MySquarer.txt in the materials posted for this chapter.) MySquarer.txt prompted for a number with the InputBox function. If a user clicks the Cancel button on the InputBox dialog box or clicks OK without inputting a number, the function returns a zero-length string ( "" ). This return value causes the sample in MySquarer.txt to fail because the CDbl function cannot convert a zero-length string to the Double data type value required by the MySquare Function procedure.

The following sample, MySquarer2.txt, remedies the problem created by the built-in CDbl function. It does so by replacing the built-in function with a custom StrToDbl Function procedure and varying the argument list for the call to the function depending on the return value from the InputBox function. The custom StrToDbl function accepts a string and returns a Double . However, if no string is passed to StrToDbl , the function uses a default value of 0. The calling procedure for the StrToDbl Function procedure omits the string input argument when the return value from the InputBox function is a zero-length string. To make this sample easy to run, we repeat the MySquare Function procedure, although the procedure does not change from its earlier incarnation in this section.

All the changes to the main procedure occur in its first segment, which gets the input from the user. The InputBox function returns its value to a string variable named str2 instead of serving directly as the argument for the CDbl function. Next the main procedure tests str2 to see whether it is a zero-length string. If str2 is a zero-length string, the procedure calls StrToDbl with no arguments. If it is not, the procedure calls StrToDbl with str2 as its argument. The function declaration line for StrToDbl shows the syntax for specifying an optional value. The procedure applies the built-in CDbl function to the value of its MyNumb argument, which equals either the string in str2 or nothing. If the call to StrToDbl does not have an argument for MyNumb , the Optional argument specification assigns MyNumb a value of 0. This returns a double with the value 0.0. The rest of the sample works identically to the earlier version.

 Sub main() Dim MyNumb As Double 'Get input. Dim str2 As String = _ InputBox("Enter a number", "Number to square") If str2 = "" Then MyNumb = StrToDbl() Else MyNumb = StrToDbl(str2) End If 'Compute output. Dim str1 As String = "The square of " & MyNumb.ToString & _ " is " & CStr(MySquare(MyNumb)) & "." 'Display result. MsgBox(str1, MsgBoxStyle.Information, "Your result") End Sub Function StrToDbl(Optional ByVal MyNumb As String = "0") _ As Double 'Return double. Return (CDbl(MyNumb)) End Function Function MySquare(ByVal MyNumb As Double) As Double 'Compute and return value for function. Return (MyNumb ^ 2) End Function 

Parameter Arrays

The next sample shows how to use one procedure to compute the area of a circle, rectangle, or trapezoid. The Visual Basic .NET code is available in the material posted for this chapter as AreaComputer.txt. The formula to compute the area for each type of shape is different. More importantly, each formula requires a different number of arguments. Parameter arrays apply to situations in which you do not know from one invocation to the next how many arguments you will need to pass. Before the introduction of overloading ” which Chapter 4 demonstrates ”parameter arrays were the only way to specify functions that required different numbers of arguments.

The following sample consists of two procedures ”a main procedure and a Function procedure named ComputeArea . The main procedure calls the ComputeArea Function procedure four times. The first three calls are to compute ”in order ”the area of a circle, rectangle, and trapezoid. The ComputeArea procedure has a formula for each of these three shapes . The fourth call to the ComputeArea procedure is to compute the area of a triangle, but the Function procedure does not have a formula for this shape. The code in ComputeArea traps this erroneous input.

The ComputeArea procedure takes two types of arguments ”a string named type , and a parameter array named Lengths . The type argument is the name of the shape. To familiarize you with String functions, this code demonstrates how to process the shape name in uppercase, lowercase, and proper case (which uses uppercase for first letter only). The most important syntax element of the sample is the use of the ParamArray keyword to designate the Lengths parameter array. You do not have to know in advance the number of arguments you are passing in a parameter array, but you do have to specify a single data type for all the elements. For example, when the main procedure calls ComputeArea for a circle, the procedure passes a single element for the parameter array to represent the circle s radius. When computing the area for a rectangle, the call statement for ComputeArea passes two arguments ”one for the rectangle s width and one for its height. The formula for the area of a trapezoid relies on three parameters ”the lengths of the two parallel lines and the distance between them. Beyond the number of parameters, the details of these formulas are not important to this sample. However, if you are curious , you can see these formulas at http://www.aaamath.com/geo.html .

 Sub main() 'Display the area of a circle. MsgBox("Radius = 7 " & StrDup(2, vbCr) & _ ComputeArea("circle", 7).ToString, , "Area of Circle") 'Display the area of a rectangle. MsgBox("Width = 7; Height = 6" & StrDup(2, vbCr) & _ ComputeArea("rectangle", 7, 6).ToString, , _ "Area of Rectangle") 'Display the area of a trapezoid. MsgBox("First parallel side = 7; Second parallel side = 3;" & _ vbCr & "Height = 6" & StrDup(2, vbCr) & _ ComputeArea("trapezoid", 7, 3, 6), , "Area of Trapezoid") 'Attempt to display the area of a triangle. MsgBox(ComputeArea("triangle", 3, 4), , "Wrong type") End Sub Function ComputeArea(ByVal type As String, _ ByVal ParamArray Lengths() As Single) As Single If UCase(type) = "CIRCLE" Then Return (3.14159265 * Lengths(0) ^ 2) ElseIf LCase(type) = "rectangle" Or type = "Square" Then Return (Lengths(0) * Lengths(1)) ElseIf UCase(Left(type, 1)) & LCase(Mid(type, 2)) = _ "Trapezoid" Then Return (0.5 * (Lengths(0) + Lengths(1)) * Lengths(2)) Else MsgBox("Type not interpretable. Enter circle, " & _ "rectangle, or trapezoid.") Exit Function End If End Function 
 


Programming Microsoft Visual Basic. NET for Microsoft Access Databases
Programming Microsoft Visual Basic .NET for Microsoft Access Databases (Pro Developer)
ISBN: 0735618194
EAN: 2147483647
Year: 2006
Pages: 111
Authors: Rick Dobson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net