## Visual Basic in 12 Easy Lessons vel15.htm

- What You'll Learn
- Introducing Subprograms
- Subroutines: Code Routines
- External .BAS Modules
- Functions Procedures
- Homework
  - General Knowledge
  - Write Code That...
  - Find the Bug
  - Extra Credit

#
Lesson 8, Unit 15

##
Subprograms

###
What You'll Learn

- Introducing subprograms
- Subroutines: code routines
- External .BAS modules
- Functions procedures

By the very nature of the material, this unit presents more theory than many of this book's other units have done. Before you can move up to the next level of Visual Basic programming, you must master certain programming techniques needed for writing large-scale applications.

Until now, each unit has added to your Visual Basic language vocabulary. So far, the more you learned, the larger your event procedure got. This unit reduces the size of your event procedures! Starting in this unit, you'll see how to break up your programs into smaller and more numerous procedures than you've seen so far.

###
Introducing Subprograms

Concept: Break your programs into as many small but logical sections as possible. The smaller routines make your programming and subsequent maintenance easier.

In many traditional programming languages such as COBOL and FORTRAN, a program is like a long book without chapters: The code goes on and on and the program's length is exceeded only by the boredom programmers face trying to wade through the code hunting down errors. You've learned enough about Visual Basic so far to know that a Visual Basic program consists of a lot more than a long program listing. A Visual Basic program consists of the following:

- A form with controls that act as the program's background and user interface
- A general-purpose procedure named (general), found in the Code window's Object dropdown list
- Event procedures that tie the controls together and add specific direction and calculations to the application
- A CONSTANT.TXT file that provides named constants used by your code

> > Note: The (general) procedure in any program's Code window is often called the declarations section.

This unit will expand on the purpose of the (general) procedure and will explain how to add different kinds of procedures to your programs.

You now know two kinds of procedures: event procedures, which execute as events occur, and the (general) procedure. The (general) procedure is really not an executable procedure in the way that event procedures execute. The only statements that you can place in the (general) procedure are data definition statements such as Dim statements and option statements such as these:

    Option Base 1

and

    Open Explicit

Many Visual Basic programmers don't worry about using the Option Base 1 statement, which, as you learned in Lesson 6, specifies that all array subscripts will begin at 1 rather than 0 (the default). Rather than use Option Base 1, most programmers just ignore the first subscript of 0 and act as if the subscripts in all arrays begin at 1.

The Option Explicit statement is a helpful statement that you can place in the (general) procedure to tell Visual Basic to look for any undefined variables and to issue an error if Visual Basic finds any. By requiring that you explicitly define all variables before you use them, misspelled variable names almost never cause the problem they would otherwise.

Assume that your program does not include the Option Explicit statement and you type the following in an event procedure:

    Dim Sales As Currency

    Sale = 294.43

    lblOut.Caption = Sales ' Outputs
    zero

Visual Basic outputs zero in the label because Sales contains zero, and the variable that you thought was named Sales, which you accidentally named Sale, holds the value of 294.43, which the user won't see.

If you were to add the Option Explicit statement in the (general) procedure (the only place you can put Option statements), Visual Basic would display the error message box shown in Figure 15.1, because Visual Basic correctly deduces that you have yet to define Sale but you're trying to store a value in Sale.

Figure 15.1. Define all variables before using them or you'll get this error.

> > Definition: Variable declaration, in Visual Basic, means the same thing as variable definition.

> > Note: The Options Environment menu displays a list of options that contain a Require Variable Declaration option that you can set to True. If a program's (general) procedure includes the Option Explicit statement, the program requires that all variables be defined before their use no matter how the Options Environment menu is set.

There are additional procedures that you can place in your programs. The general name for these procedures is subprogram. These procedures, just like the event procedures, are like small versions of a Visual Basic program. In a way, all procedures are the building blocks of the overall application code because all the procedures work together to comprise the complete application.

There are two kinds of Visual Basic subprograms: subroutine procedures and function procedures. Often, we abbreviate subroutine procedures to just subroutines and we abbreviate function procedures to functions. This may cause confusion due to the built-in functions such as Int() that you read about in the previous lesson. This book reserves the term function procedure, or just function, for the function procedures that you write, and this book refers to the functions supplied by Visual Basic as the built-in functions, as has been the case throughout the earlier lessons.

> > Note: Event procedures are actually specialized subroutine procedures. It's important, however, to distinguish between event procedures and the general-purpose subroutines you'll write that aren't tied to events. Therefore, this book will continue to refer to event procedures by that name, and this book will refer to subroutine procedures either subroutine procedures or just subroutines.

Review: This section, as well as most of this unit, is concerned with getting the terminology straight that you'll read about and use throughout the rest of this book. Visual Basic programs are actually just small sections of code named subprograms that you write and that appear along with a (general) definitions section. There are two kinds of subprograms: subroutine procedures (which include event procedures) and function procedures. The rest of this unit explains more about these Visual Basic program divisions and also explains how to store subprograms in external files that more than one Visual Basic application can share.

###
Subroutines: Code Routines

Concept: A subroutine procedure always begins with the Sub statement and always ends with the End Sub statement. A subroutine procedure may or may not be an event procedure. Non-event procedures are general-purpose subroutines that you can write and add to any program.

Listing 15.1 contains an event procedure that you've seen in almost every program in this book.

Listing 15.1. A common event procedure.

    1: Sub cmdExit_Click()

    2: End

    3: End Sub

> > Definition: Wrapper lines are lines of code that start and terminate procedure.

Lines 1 and 3, the wrapper lines, confirm that the Exit command button's Click event procedure is a subroutine procedure, as mentioned previously.

Event procedures are specific subroutines tied directly to control events. There will be times, many times in fact, when you'll write subroutines that aren't tied to any events whatsoever. When you write a section of code that your application will have to execute more than once, that section of code is a great candidate for a general-purpose, non-event subroutine.

> > Definition: To call a subroutine means to execute the subroutine from elsewhere in the program.

Suppose that your company has a specialized routine for calculating a cost of sales value. In writing a sales-computation data entry program, you find that you must execute this code several different places in the program. In other words, you never execute the routine over and over in a loop; instead, you may find that three or four different event procedures need to include this same calculation. Rather than type the exact code in three or four different places, type the code just once in its own subroutine and call that subroutine from each event procedure that needs the calculations.

Follow these steps to create a non-event subroutine procedure:

1. Make up a name for the procedure using the same naming conventions that you use for variables. Be sure to name the subroutine something meaningful. If you were computing cost of sales, the name CostOfSales would be a perfect name.
2. Open the Code window if it's not already open.
3. Press the PgDn key or click the Code window's vertical scroll bar to move the Code window down to the end of any event procedure. In other words, position the Code window's text cursor to the end any End Sub statement that you can find.
4. On a blank line below the End Sub statement, type the Sub statement followed by your new subroutine name. In other words, you would type Sub CostOfSales after any event procedure's End Sub statement.
5. As soon as you type the Sub statement, Visual Basic recognizes that you're starting a new subroutine. Visual Basic finishes the End Sub wrapper line and displays your new subroutine by itself in the Code window, as shown in Figure 15.2.
   If you were to open the Proc dropdown list, you would see the new CostOfSales general purpose subroutine among the list of procedures.

   Figure 15.2. Visual Basic gives your subroutine its own place in the Code window.

   > > Note: Notice that Visual Basic always adds parentheses after all subroutine names. Nothing you do will get rid of those parentheses. You'll use those parentheses in the next unit.

6. You can now insert the body of the subroutine in the middle of the two wrapper statements. As you add a line and press Enter, Visual Basic adds additional lines, so the subroutine grows as large as needed. Listing 15.2 contains a sample cost of sales subroutine that could be used for the procedure.

Listing 15.2. The cost of sales subroutine.

    1: Sub CostOfSales ()

    2: ' Computes a cost of sales and displays

    3: ' that cost in the appropriate label

    4: Dim GrossSales As Currency

    5: Dim CostSales As Currency

    6: Dim OverHead As Single

    7: Dim InventoryFctr As Single

    8: Dim PilferFctr As Single

    9:

    10: ' Store initial values from the form

    11: GrossSales = txtGross.Text

    12: InventoryFctr = txtTotalInv.Text * .38

    13: PilferFctr = txtPilfer.Text

    14: OverHead = .21 ' Fixed overhead

    15:

    16: CostSales = GrossSales - (InventoryFctr * GrossSales)

    17: CostSales = CostSales - (PilferFctr * GrossSales)

    18: CostSales = CostSales - (OverHead * GrossSales)

    19: lblCost.Caption = Format$(CostSales, "Currency")

    20: End
    Sub

Figure 15.3. You can use the New Procedure dialog box to open a new procedure.

Although the body of the cost of sales subroutine is only 18 lines long, you certainly don't want to type those same 18 lines in every event procedure that needs to execute those 18 lines. If you've typed the code in its own subroutine as shown in Listing 15.2, you never have to type that code again. Instead, you'll just call that subroutine from every place in the program that needs the code executed.

> > Tip: You can take a shortcut when you want to open a new procedure. Select the View New Procedure from the menu bar. Visual Basic displays the small New Procedure dialog box shown in Figure 15.3. Clicking Sub opens a new subroutine procedure, and clicking Function opens a new function procedure (described later in this unit). Type the new procedure name in the Name text box and click OK. Visual Basic will open the new procedure and type the wrapper lines for you.

The Call statement executes subroutines. Here is the format of Call:

    [Call] subName [(argumentList)]

Unit 16 describes the use of the argumentList. Not all procedures will contain an argument list. Call is optional, but if you do use the Call keyword when you call subroutines, you also must include the parentheses. Just remember: If no Call, no parentheses; if Call, use parentheses. Either way, the argument list may or may not be required.

> > Tip: You can move from procedure to procedure inside the Code window using the PgUp and PgDn keys. If you press F2, the shortcut access key for the Window Procedures command, Visual Basic displays a list of procedures; select a procedure and Visual Basic takes you to that procedure in the Code window.

You'll learn about the argument list in the next unit. For now, concentrate on the use of Call. Whenever any procedure in your program needs to trigger the execution of the CostOfSales subroutine, you'll only need to code the following Call statement:

    Call CostOfSales () ' Executes all of the subroutine

The following statement is equivalent because, without Call, you don't need the parentheses:

    CostOfSales ' Executes all of the subroutine

If three different procedures need the cost of sales routine calculated, isn't it easier (and less error-prone) to type the code once in its own subroutine and then simply call that subroutine from every place in the program that needs it? You can call subroutine procedures from event procedures as well as from other non-event subroutine procedures. Figure 15.4 shows the program flow when several event and subroutine procedures call the CostOfSales procedure. When one of the calling procedures calls CostOfSales, the CostOfSales takes over, executes, and the program's execution flow continues where it left off before taking time off.

Figure 15.4. The subroutines work like detours inside your program.

The Call statement also executes event procedures. You can, even if the user didn't trigger an event, trigger any event from within the code by using Call to execute the event procedure. Suppose that the Exit command button performs several end-of-program tasks such as erasing the form, asking the user's permission to exit inside a message box, writing the last of data files to disk, and printing a final report on the printer. If you find that you need to perform a program exit even if the user has yet to click Exit, you can call the cmdExit_Click() event procedure yourself.

> > Note: If you ever need to exit a subroutine procedure before the procedure's normal termination—for example if the user cancels a subroutine input box—use the Exit Sub statement.

Review: When the same set of code lines needs to appear in more than one location in your program, consider putting those lines in their own subroutine procedure. You'll need to start a new procedure only if you use the Sub" or select the New Procedure command from the View menu. Place a Call to the subroutine procedure in all other program locations where you want the subroutine code to execute. You can call either a subroutine procedure or an event procedure using Call. When Visual Basic completely executes the procedure, Visual Basic returns execution to the code that performed the Call, and execution resumes at the statement following the Call.

###
External .BAS Modules

Concept: Over time, you'll write several routines, such as the previous section's CostOfSales subroutine procedure, that you will need in more than one application. Rather than write the same subroutine procedure in every application, you can store the subroutine procedure in a module file, along with other common procedures that you write, and add that file to any application that uses the file's procedures.

> > Definition: A module contains a form and the procedures used by that form.

Every program that you've seen so far in this book has consisted of single modules. A module is a collection of all event procedures, subroutine procedures, and function procedures, along with a form holding the controls. With the Visual Basic Primer system, you can add additional code modules to your form's module. A code module is an external file, stored separately on the disk, that contains the code of procedures that you write. These procedures are general-purpose procedures that perform calculations on data that you'll soon learn to pass to and from those procedures.

The CONSTANT.TXT file is a specialized kind of module that contains only a (general) procedure. Although you could add additional procedures to CONSTANT.TXT, you should neither add nor take away from the contents of CONSTANT.TXT. With each version of Visual Basic that Microsoft releases, Microsoft updates the contents of CONSTANT.TXT, and you'll want to replace the old CONSTANT.TXT file with the new one when and if you upgrade to a different version of Visual Basic.

You can add additional code modules to your program by selecting File New Module (or by clicking the New Module toolbar button, the second toolbar button from the left). As soon as you request a new module, Visual Basic opens a new Code window for that module. Visual Basic automatically names the first module that you add MODULE1.BAS (adding that file to the Project window's file list for that application). If you were to add a second module, Visual Basic would name that module MODULE2.BAS, and so on. Figure 15.5 shows the new Code window that opens when you add a new module to an application.

Figure 15.5. The new Code window from the MODULE1.BAS external module file.

Once you add code to a module file, you should save the file under a name that's different from the default name. Keep the .BAS file extension, however. The .BAS filename extension is usually reserved in Visual Basic for the general purpose external module files that you'll write and use. Even though CONSTANT.TXT is an external module file that breaks the .BAS file-naming rules, CONSTANT.TXT is an external module file.

The Project window for each application reflects which form file and module files (as well as CONSTANT.TXT if you use it) that each application requires. When you create a module, you're creating a stand-alone file on the disk that more than one application can use as long as you add that module to the applications' Project windows.

> > Note: Remember that the Project window doesn't hold files. The Project window holds only an application's list of needed files. You'll have to ensure that you distribute your Visual Basic applications with all files listed in each application's Project window (described in the .MAK file) if you write and distribute your Visual Basic applications to others.

Suppose that you wrote several subroutine procedures that printed your company's name and address, calculated city sales taxes for sales in all of your division's 20 regions, and made a backup of data files if the date hits the first of the month. You may find that, although you originally wrote these procedures for a general ledger system that you were writing, you need those same procedures in other programs. You can open a new module from within the general ledger application's Code window, and cut and paste those procedures from the general ledger application to the new module. If you then saved the module under the name MYPROC.BAS, the general ledger application would be able to call that module's procedures (owing to the fact that Visual Basic added the module to the Project window when you first created the module), as well as any other application to which you selected File Add and added the MYPROC.BAS module to.

All programs automatically contain a form module. The module that you work in, using the Code window, that always displays when you open a form's or control's event procedure, is the form module. Additional modules that you add to the application, as well as the module supplied in CONSTANT.TXT, are sometimes called non-form modules.

Review: Over time, you'll create module files when you run across useful procedures that you might need elsewhere. You can have as many modules on your disk as you want and add any or all of them to subsequent applications that you write. In a way, you're then building new applications faster by reusing code (through the Call statement) that you wrote for other applications and stored in the general-purpose modules.

###
Functions Procedures

Concept: As with the built-in functions, you can write your own general-purpose function procedures, often just called functions, that aren't tied to specific events. You can call these functions from your Visual Basic application. You can place these functions in their own external code modules or add them to an application's Code window. Function procedures work a lot like subroutine procedures; you can call them from elsewhere in the program. Unlike subroutine procedures, however, function procedures return values.

You can write your own function procedures to augment the built-in procedures supplied by Visual Basic. If you run across a needed calculation that converts a needed measurement, and you feel that you'll need that same conversion several places in your program, add that code to a function procedure. The function will be able to make the calculation and return the answer for the calculation to the calling routine.

As explained in the previous lesson, "Functions and Dates," when you call built-in functions, you must do something with the return value. You can't code the Int() function on a line by itself like this:

    Int(Amount) ' Invalid!

Int(Amount) will return the amount converted to an integer, and you must do something with the returned integer. Therefore, you'll usually assign the return value like this:

    lblAmt.Caption = Int(Amount)

or you'll use the function in a calculation that needs the value like this:

    WholePart = Int(Amount) +
    Estimate

You can write the code for your own numeric and string function procedures and add them to Visual Basic's repertoire. The functions that you write aren't quite as built in as Visual Basic's built-in functions because your functions don't become part of Visual Basic's language. Nevertheless, as with subroutine procedures, you can code the function procedures inside your application's Code window as well as store function procedures by themselves or along with subroutine procedures in external modules so that more than one application has access to the functions.

To write a new function procedure within a Code window, whether that Code window is your application form's Code window or an external .BAS module that you've opened, you can select the View New Procedure from the menu and click the Function option button on the New Procedure dialog box. (In the previous section, you clicked Sub to open a new subroutine.) After you type a new name for the function in the Name text box, Visual Basic adds the function wrapper lines like the ones shown here for a new function procedure named MultiplyIt:

    Function MultiplyIt ()

    End Function

A function procedure always begins with the Function statement and ends with the End Function statement. You'll add code to the body of the function between the two wrapper lines.

> > Tip: If you add a dollar sign after the function name, such as Reverse$(), Visual Basic assumes that you want to open a string function that will return a string value. If you omit the dollar sign, Visual Basic assumes that your function will return the Variant data type in which you can return numbers or string values. To keep things clear, always use the dollar sign for string functions.

A function is the same in every way as a subroutine except that the function returns a value. To return the function's value, assign the return value to the name of the function. Don't use Call to call a function. All you do to call a function is to use the function procedure's name inside an expression or statement.

> > Note: If you ever need to exit a function procedure before the function's normal termination—for example, if the user cancels an input box—use the Exit Function statement.

Stop and Type: Listing 15.3 contains a function that computes the postage for a letter or package as follows:

1. The Post Office charges 32 cents for the 8 ounces.
2. Add 15 cents for each additional 4 ounces above the first 8.
3. The weight must be below 24 ounces.

Listing 15.3 assumes that the letter or package weight appears in a text box control named txtWeight.Text. In addition, the weight must appear as ounces. Therefore, any application that uses this function must make sure that a text box named txtWeight exists and holds the total package weight before calling the function.

Review: When you want special routines that calculate or manipulate string values, and Visual Basic doesn't supply those routines through internal built-in functions such as CInt() and Mid$(), write your own function procedures. Before the function procedure terminates, assign the function's return value to the name of the function. Visual Basic uses this mechanism (the assigned name) to return the value assigned to the name back to the calling code that needs the result.

Listing 15.3. A function that calculates postage and returns the cost.

    1: Function Postage ()

    2: ' Calculate postage based on the

    3: ' weight of a letter or
    package

    4: Dim PostHold As Currency

    5: Dim weight As Integer

    6:

    7: ' Grab the weight value from the text box

    8: ' and convert to number for comparison

    9: weight = Val(txtWeight.Text)

    10:

    11: Select Case weight

    12: Case Is <= 8:

    13: PostHold
    = .32

    14: Case Is <= 12:

    15: PostHold = .47

    16: Case Is <= 16:

    17: PostHold = .62

    18: Case Is <= 20:

    19: PostHold = .77

    20: Case Is < 24:

    21: PostHold = .92

    22: Case Is >= 24:

    23: MsgBox "Weight is more than 24 ounces!",
    MB_ICONEXCLAMATION, "Error"

    24: PostHold = 0

    25: End Select

    26:

    27: Postage = PostHold ' Return the value

    28: End Function

Analysis: Line 3 defines a variable that will hold an interim postage amount throughout the Select Case. Actually, the extra PostHold variable is not strictly needed because each Case could assign directly to the function name. Nevertheless, assigning to the function name at the bottom of the function makes for better self-documentation of the code. When the function finishes, line 26 completes the function's task by assigning the calculated value to the function name.

> > Without Sharing, Your Code Is Limited: This unit's discussion of subroutines and functions can only be complete once you master the next unit's material on passing of data from procedure to procedure. Until now, a procedure could only work with data defined inside that procedure. The only exception was the function procedure that you just learned about, in which one procedure can use a value returned from another.
> > The next unit shows you how you can share variables between functions. The controls that you've been using have been available to all procedures in your program but not the variables. Only when you learn how to pass data from one procedure to another can you see the real power of subroutine and function procedures.

###
Homework

####
General Knowledge

1. True or false: A subroutine procedure is the same as an event procedure.
2. How do you call subroutines?
3. How do you call function procedures?
4. Name two ways that you can begin entering a new procedure in the Code window.
5. How can you determine whether a function procedure returns a string or a variant data type?
6. What is the primary difference between a subroutine procedure and a function procedure?
7. How do you indicate the return value of a function?
8. What is the shortcut access key to move from procedure to procedure?
9. How does a programmer-defined function procedure differ from a built-in function?
10. What is the name for a file that holds general-purpose procedures?
11. What filename extension should module files have?
12. Name a limitation of the procedures given your current knowledge so far. (Hint: Read the last sidebar in this unit.)
13. Name two statements that can appear in the (general) procedure.
14. True or false: You can call event procedures from other event procedures.
15. True or false: You can call event procedures from subroutine procedures.

####
Write Code That...

1. Write the two wrapper lines for a subroutine procedure named PrReport().
2. Write the two wrapper lines for a function procedure named GetValue().
3. Suppose that you were writing a function named GetPi() that returned the value of the mathematical pi (which is approximately 3.14159). Write the statement that returned the value.

####
Find the Bug

1. 19. Describe what's wrong with this Call:
   Call MySub arg1, arg2

####
Extra Credit

Write a string-reversal function named Reverse$() that takes the string stored in the text box named txtAString and reverses the string, returning the string in the function name of Reverse.