Hour 13


During this hour you will learn

Understanding How Procedures Work

This lesson finally gives the details of Sub and Function procedures. Until now, you've worked with procedures and have had little trouble with them, but you've never been explained the full reason for the parentheses or the implications of subroutine and function differences. When you learn to write your own subroutine and function procedures, you'll better understand the built-in functions that Visual Basic supplies, such as InputBox().

This lesson reviews data storage and explains more about local and public variables. You don't see the need for separate subroutine and function procedures until you see that local variables require extra work when you need to use the same local variable in two different procedures.

Topic 1: Variable Scope Revisited

As you've seen, modules often contain multiple procedures. A form module might hold several event procedures 7Äone or more event procedures for each control on the form. Also, the form module might contain general procedures. The standard modules that also appear in applications usually contain multiple procedures. These procedures might be functions or subroutines.

When a module contains multiple procedures, those procedures often have to share data among each other. Creating a variable in one procedure with Dim doesn't automatically make that variable available in other procedures. You must understand how procedures share data when needed.

FAST TRACK
Do you understand local and global variable scope? If so, jump to the topic section "Passing Data Between Procedures" to learn how Visual Basic programs transfer data from one procedure to another. If you've already mastered the local, module-level, and public variable details, as well as written Visual Basic function procedures, you may as well go right on to next hour's lesson, "Using the Supplied Functions".

Overview

As a Visual Basic programmer, you have to know how your module and procedure variables interrelate. This lesson explains how multiple procedures locate variables that are available to them. Although you already know to use the Project menu's AddModule option to add new standard modules to a project, this topic section explains more about why you'd need additional modules within an application's project. When you more fully understand the need for multiple modules and procedures here, the next topic section will show you how to communicate between procedures through shared variables.

A Code Review

A simple application contains a single form with event procedures. Those event procedures appear when you choose Code from the View menu (or when you click the Project window's View Code toolbar button). The code you see might appear all together, separated by dividing lines, as Figure 13.1 shows. The code's procedures might also appear one at a time in the Code window as you press Page Up and Page Down or select the procedure you want to display from the drop-down list boxes at the top of the window.

FIG. 13.1

A Code window displays the form module's procedures.


Remember that you can switch between the Full Module View and the single Procedure View by clicking the appropriate button at the bottom of the Code window.

If all a form module contains are event procedures, you don't have to worry about sharing data between the procedures. All modules, including form modules, contain a Declarations section that you can view by selecting General from the Object drop-down list box and Declarations from the Procedure drop-down list box. You often have no need to declare data in the Declarations section if your application includes only one form with procedures that are only event procedures.

As you've seen throughout the earlier lessons, a Declarations section might contain special code other than variable declarations, such as the Option Explicit statement. A Declarations section, however, can't contain anything other than variable declarations and these special Option statements. All your executable code that contains loops and If statements must appear in procedures within the modules and outside the Declarations section.


All modules contain a Declarations section even before you add procedures to the modules. You never have to add a Declarations section yourself because one will always be available to you.

Adding More to Procedures

If you begin to expand the code inside the event procedures-by declaring variables and adding looping instructions to the event procedures-you may find that you want two or more procedures to work with the same variable. For example, one command button's Click event procedure might store a True value in a Boolean blnWasClicked variable so that another event procedure will know if the command button was ever clicked. Suppose that you declare the variable inside the procedure like this:

Private Sub cmdSalesOver ()

  Boolean blnWasClicked

  blnWasClicked = True   ' Let other procedures

                         ' know about the click

  ' Rest of event procedure goes here

End Sub

No other procedure can know about the variable! blnWasClicked is local just to that procedure because you declared blnWasClicked inside the procedure. If you want certain other procedures to know about blnWasClicked, you must move its declaration out of the procedure and into the module's Declarations section.

When you declare variables inside a procedure's Declarations section, that variable is available to all the procedures in the module. Therefore, with only one form module, if you declared blnWasClicked in the form module's Declarations section, every event procedure can use blnWasClicked and they will all know what value blnWasClicked holds at any time.

Adding Complexity

You now can declare two kinds of variables:

It's actually more accurate to call these global variables module-level variables because the variables you declare with Dim in the Declarations section is available to all procedures within that module.

If you begin to add additional modules to your project, such as additional forms that contain their own form modules and additional standard modules that hold general-purpose routines that you might use in several applications, you may find that the module-level sharing of variables isn't wide enough in scope for your needs. You may want to access one module's variable from another module. If so, you need to declare truly global variables, called public variables in Visual Basic, with the Public keyword.

Although Hour 8 explained the format of Public (the format is identical to Dim), you didn't understand the true purpose for Public until now. Public declares application-wide global variables.

You may declare public variables only inside a module's Declarations section.

Therefore, if you declare the Boolean variable inside one of your module's Declarations section like this:

Public blnWasClicked As Boolean

the blnWasClicked variable is available for use within any procedure and from any module in the entire application.

Applications with Multiple Projects

Visual Basic supports the Declarations section statement Options Private Module. Not only can any procedure from within any module access public variables normally, but any other project can as well. Visual Basic supports the creation of host applications that can work with multiple projects at one time. If Options Private Module is present, however, the public variable you declare is available only to its specific project and not to any outside projects. Generally, even the most advanced and powerful applications don't use multiple projects so you'll rarely, if ever, need to bother with the Options Private Module statement.

Problems Now Arise

It's been said that with power comes responsibility. The more public a variable becomes-from local to module-level to public-the more easily your programs get cluttered and the more easily bugs enter the picture. Although public variables sound useful, rarely does an application need to use public or even module-level variables. More typically, only two or a few procedures need to share the same data values, and the other procedures don't need access to those variables. If, for example, a report procedure prints values read from the disk in another procedure, only those two procedures need to know the values.

Too often, reusing the same variable name for two different purposes (such as a For...Next loop's counting variable) is too easy. If that variable is declared with Public or even as a module-level variable, you can replace a value that was assigned and is still in use in another location in the application.

Local variables are visible (usable) only from within the procedures in which you declare them. If you use the same local variable name in one procedure as a variable local to another procedure, you don't damage the other's copy of the variable. Keep in mind that without Option Explicit in a module's Declarations section, you don't even have to declare a variable but you can just begin using one. Visual Basic will assume that the variable is of the Variant data type. Therefore, you may be lulled into thinking that you're using a variant variable but in reality you had already declared that same public variable name elsewhere and you're changing the variable's contents instead of using a newly formed variant variable.

Even procedures have scope. Generally, procedures have private scope (indicated by the Private keyword that precedes function and procedure declarations), meaning that only procedures within that same module can use the procedure. If you declare a procedure by using Public instead of Private, all variables in all modules can use that procedure. Generally, procedures within a standard module (as opposed to a form module) are public so that any application you add the standard to can use the routines inside that module.

Declaring local variables and private procedures becomes especially critical when you work on a Visual Basic program with other developers. If you and another programmer are writing modules that operate on the same data in the same application, you could write a procedure or create a variable that has the same name as the other programmer's code. If, however, all your data is local and your procedures are private, name clashes never occur because your module's variables and procedures are accessible only within the module that you write. Despite the name-clash advantage, however, some of your standard module's procedures can't be private because such procedures can't be triggered from a form's event procedures; instead, they can be triggered only from other procedures in the standard module.

The Local vs. Public Implications

Here's where you now are: You've seen that variables can be very local or very public. You've seen that routines often need to share data. You've also seen, however, that sharing data publicly or even on a module-level is dangerous and that you should avoid declaring anything other than local variables.

The dilemma is this: You need to share data between those procedures that need to share data, but you're not supposed to include module-level and public variables in your applications! How can you share data and still keep your data local? The next topic section explains how to give variable-sharing access only to those procedures in the application that need access. Your variables will then receive shared data values only on a need-to-know basis.

Example

Suppose that you run across an application with the following Declarations section:

Dim a As Integer

Public b As Single

You know that a is a module-level variable and that only that module can use a. All procedures within the module have access to a and can change or display the value in a.

You also know that b is a public variable whose scope is broader than that of a's. Any procedure within the module can access b as well as any other module's procedure! In fact, without the Options Private Module statement before the variables, any project in a multiple-project application (as mentioned earlier, these are rare) has access to b. Therefore, b is in potential trouble due to its widespread exposure. Sure, all procedures can share b, but that also makes b susceptible to inadvertent damage.

Next Step

Figure 13.2 illustrates all the scoping possibilities that variables and procedures can posses. Notice that both modules' public variables are accessible from within both modules.

FIG. 13.2

Different variables can have different scope.

Keep all your public variable declarations together (if you use any at all) within one module-unlike the illustrative example in Figure 13.2-so that you can keep track of them more easily. Remember, however, to limit your use of public variables. Local variables don't get in each other's way as easily as public variables, and public variables consume memory for the entire module's life rather than during a single procedure's execution; that's why you can declare public variables only in the standard module.

In Figure 13.2, the variables a and b have module-level scope and are visible and usable only from within their module's procedures. Each procedure contains its own local variable (such as L1 and L2a) and, because they're local, only those procedures can access those local variables.

The PM1b procedure is a Private procedure, as is PM2b, so they can be called only from another procedure within their own modules.

Topic 2: Passing Data Between Procedures

Local data is much safer than global data. In the first topic section, you learned that the location of the variable's declaration is the primary determinant of a variable's scope. When you're writing a system with other programmers, using local variable data becomes even more critical. If two of you use many global (public) variables, and you both happen to use the same names, a name clash occurs.

Overview

Given the premise that local variables are good, and given that local variables can be used only in the procedure in which you define them, a problem arises when you need to write modules that contain multiple procedures. Just because procedures are separate doesn't always mean they have to work with separate data.

Suppose that one procedure calculates an array of data that another procedure is to print. Yet, if the array is local to the first procedure, the second procedure can't use the variable. Neither subroutine nor function procedures can use each other's local data-at least, not until you set up a sharing mechanism between them. This topic explains how you can share only certain variables while maintaining the safety of locality.

Name Clashes

If two public variables named pi are declared-one for your procedure and one for someone else's procedure who is working on your same application-Visual Basic can't know which pi you're initializing when you type the following:

pi = 20

If you use a public variable and another programmer on the same application uses a local variable with the same name, the local variable always hides the scope of the public variable. When the local variable goes out of scope (which means the variable is no longer available for use when the procedure ends), the public variable is then used whenever the name is referred.

Figure 13.3 helps illustrate that happens when a local and a public variable have the same name.

FIG. 13.3

Local variables overshadow public variables with the same name.


Use only local variables to solve the problems of name clashes and local variables hiding the scope of public ones.

Two or more local variables residing in two separate procedures can have the same name. You never have a problem with name clashes if you stick to local variables. The variables are known only in the procedures in which they should be known, and one procedure doesn't have improper access to other procedure's variables.

These local versus global issues apply to you even if you don't work in a team environment and write full applications yourself with Visual Basic. Too often programmers reuse a variable name that they've already declared. If the variable is local, using that same name for local variables in other procedures hurts nothing. If the variable is public, however, using the name will almost surely damage another procedure's value.

Sharing Data

When two procedures share local data, one procedure (called the calling procedure) passes data to the second procedure (called the receiving procedure). Figure 13.4 shows what you do when you need a local variable to appear in two or more procedures. If the receiving procedure computes or modifies a value that the calling procedure needs, the receiving procedure can return that value back to the calling procedure.

FIG. 13.4

Calling procedures pass local data, and receiving procedures work with that data.

Never pass a public variable, because Visual Basic will get confused. There's no reason to pass public variables anyway because they're already visible to all functions.

When you pass a local variable from one procedure to another, you pass an argument from the calling procedure to the receiving procedure. You can pass more than one argument (variable) at a time if you want several local variables sent from the procedure that sends them. The receiving function is said to receive a parameter (variable) from the sending procedure.

You shouldn't worry too much about what you call these passed variables-either arguments or parameters. The important thing to remember is that you're sending local variables from one procedure to another.

You've already passed arguments to procedures-you did so when you passed data to the MsgBox() and InputBox() functions. The constants, variables, expressions, and controls that you passed inside the parentheses are arguments. The built-in MsgBox() and InputBox() functions receives these values (called parameters on the receiving end) and displays them.

The parentheses work to hold either the sent data for sending procedures or the received data values for receiving procedures. To pass a local variable from one procedure to another, you must place the local variable in parentheses in the calling procedure and in the receiving procedure. If the parentheses are empty, nothing is being passed to the procedure. The receiving procedure might declare the incoming data inside the parentheses as so,

Private Function  R(v1 As Variant, v2 As Variant, v3 As Variant)

or the receiving code will assume Variant unless the data types you specify vary. All received data is treated like local variables in the receiving procedure.

Sub Procedures vs. Function Procedures

Sub procedures work just like Function procedures, with the following exception: A Sub procedure never returns a value and a Function procedure always returns a value. Therefore, subroutine procedures receive data in one direction only, whereas function procedures receive as well as return data.

The built-in function's arguments work exactly like procedure arguments but because the code for the built-in functions isn't part of your module, you must pass all data to built-in functions. The built-in functions even require that you pass public data. For example, you must pass whatever data you want MsgBox() to display, even if that data appears in a public string inside your procedure. MsgBox() can't read your mind and needs to know what kind of data to display.

If you need to exit a procedure earlier than its normal End Function or End Sub would exit, use the Exit Sub and Exit Function statements. Generally, you'll use Exit Sub and Exit Function inside the body of an If statement that exits only if certain conditions (such as missing data) occur.

By Reference, By Value

If Figure 13.4's R () procedure changes any of its arguments (v1, v2, or v3), the corresponding variables in C () are also changed by their receiving procedure. By default, all Visual Basic procedures pass data by reference, meaning that the passed arguments can be changed by their receiving procedure. If you want to keep the receiving procedure from being able to change the called procedure's arguments, you must pass the arguments by value. To pass by value, precede the receiving variable arguments with the with the ByVal keyword or by enclosing the passed arguments in parentheses.

Example

The following short examples test your knowledge at recognizing calling and receiving procedures. Being able to recognize the differences is half the battle of understanding them.

Private Sub doIt() is the first line, called the procedure declaration line. The keywords Private and Sub let you know that. No arguments are ever to be passed to doIt(). If you omit the Private keyword, Visual Basic assumes private as in

Sub doIt()

The statement

Call doIt2(curSales)

calls a procedure named doIt2() and passes that procedure the value of curSales. Visual Basic supports an optional Call keyword alternative; if you omit Call, you must also omit the parentheses, as in

doIt curSales

Always use Call for procedures to clarify the argument list. You don't use Call for built-in functions, such as InputBox(). Always use parentheses around the arguments when calling built-in functions unless the functions require no arguments.

The following statement is a receiving procedure named doIt3():

Private Sub doIt3(ByVal curSales As Currency)

The procedure receives one argument-a Currency data type. If doIt3() changes curSales from the passed value, the calling procedure's value doesn't change due to the ByVal keyword (only the value of curSales is passed, not the variable itself).

The following statement works just like doIt3(), except its argument is received by reference:

Private Sub doIt4(ByRef curSales As Currency)

Because ByRef is the default, the following statement is identical to the previous one:

Private Sub doIt4(curSales As Currency)

If you omit the As Currency option, doIt4() will assume that it's receiving a Variant data type, which, in many instances, works just fine.

Next Step

Suppose that you're writing a procedure that needs to call the following subroutine procedure:

Public Sub Area (Radius)

  Dim sngCirArea As Single

  sngCirArea = 3.14159 * Radius * 2  ' Compute area of a circle

  MsgBox ("The area is " & sngCirArea)

End Sub

To call this subroutine, you can do the following from another procedure:

Call Area (3.4)    ' Call the sub procedure

Visual Basic supports a shortcut for calling subroutine procedures. You can omit both Call and parentheses like this:

Area 3.4    ' Call the sub procedure

Such calling statements can be confusing, however, so stick with Call when you can.

Topic 3: Returning Values from Functions

You know how to pass data but don't yet know how to return data back from function procedures. Until now, most procedures in this book have been Sub procedures, which are called from another procedure but don't return any values. A function procedure returns only one value back to the calling procedure.

Overview

Functions that return values offer you a new approach to programming. In addition to passing data one way-from calling to receiving procedure-you can pass data back from a receiving function procedure to its calling procedure. In Visual Basic, the way you return a value is to assign that value to a variable named the same as the procedure.

Why Only One Return Value?

A function can, as can a subroutine, receive zero, one, or multiple arguments. That is, you can write a function that accepts no arguments by typing empty parentheses after the function name. You can write a function that accepts one or more arguments by specifying those arguments in the parentheses as indicated in the preceding topic sections. The same can be said of subroutine procedures as well.

The distinction between functions and subroutines, as you now know, is that a subroutine never returns a value but a function does. Other than the return value, functions and subroutines are procedures, both can contain any Visual Basic statement, both can call other procedures, and both can be called.

A Sub procedure is useful for routines that perform common work. Suppose that you display a special series of input boxes that set up users' data-entry sessions for a bookstore. The input boxes might ask users for an employee ID, a password, and a shift code; then the application might display an empty form that accepts the first book's data. Although your application could have asked users for the three initial values with a second form that contains text boxes, the extra form would be overkill; the input boxes seem to make the most sense for those three values.

Suppose that you want to use this same series of input boxes in several of your bookstore's applications. If you write the code that manages the input boxes and store the code as a Sub procedure inside a standard module, you then can add that module to whatever application needs the three input boxes. That application could then, from different places in the application, call the subroutine. Four places in the code might call the subroutine to trigger its execution, but the subroutine's code appears only once.

A function is useful when a calculation or data manipulation must occur. Suppose that your bookstore's accounting records require a long series of calculations to be performed to come up with a day's total net adjusted sales. Perhaps the calculations required four values: gross sales, tax rate, gross returns, and the average daily store expense. Although you could pass these four values to a subroutine procedure, how would the calling procedure know the result of the calculated answer? If you use a Sub procedure, you have only two inelegant ways to get the answer back from the procedure:

A function procedure takes care of the problems nicely. You can pass the four argument values to the function as you would with a subroutine. The function, however, would specifically return the calculated value back to the calling code. No name matches would need to take place; your calling code can grab the return variable and store the value in any variable needed.

Functions always return only single values. As you'll see in the next topic section, you can't really set them up to return more than one value because there would be no way to capture multiple return values from a function.

If you've studied mathematics, you've no doubt studied functions that take on the notation f(x). Mathematical functions return only one value no matter how many arguments (the x and additional parameters that might be needed) you pass to them.

Setting Up Function Procedures

A Function procedure declaration requires only a slight difference from a Sub procedure. You must tell Visual Basic the data type of the function's return value. Here is the general syntax:

Public Function FunName([Arg As DataType][, ...]) As FunDataType

Many functions are public, especially the ones in standard modules, so you can call them from elsewhere in the module. Notice the final two components, As FunDataType. When writing function declarations, you must indicate the function's return data type. The function will then return a value based on that data type.

Therefore, the preceding section's net adjusted sales calculation function's declaration line might look something like this (the line is long to hold all the arguments):

Public Function CalcNetAdj(curGrSls As Currency,

[ccc]sngTaxRt As Single, curGrRet As Currency,

[ccc]curStrExp As Currency) As Currency

The final As Currency tells Visual Basic that the function's purpose is the return a single currency value.

Making the Return

Visual Basic uses a simple method to setup the return value. Somewhere in the function, you'll assign the return value to a variable that has the same name as the function name. You won't declare this variable, but you can use it. Therefore, if the final calculation inside the CalcNetAdj () function subtracts the average daily store expenses from a local variable named curTempHold, you can assign that expression directly to the function name like this:

CalcNetAdj = curTempHold - curStrExp

This line tells Visual Basic to send back the value, stored in CalcNetAdj, to the calling procedure. Although one or more statements might follow this assignment in the function, the assignment to the function name is usually the final line in a function. When the function ends at the End Function statement, the value is sent back to the calling procedure.

The calling procedure, therefore, must supply a place for the return value. Generally, you'll assign the returned value to a variable. In the calling procedure, it's not unusual to see a statement such as this:

curDailyNet = CalcNetAdj(curGrSls, sngTaxRt, curGrRate, curStrExp)

The calling procedure runs along until it gets to this assignment statement. Visual Basic then puts the calling procedure on hold and executes the function named CalcNetAdj(), passing the values to the function. When the function returns the calculated value, the calling procedure then gets the function's return value and stores that value in curDailyNet. The calling procedure can then keep executing. In other words, to complete this assignment, the function must execute and get a return value.

The calling procedure doesn't have to use the same variable names in the argument list as listed in the function argument list. A calling procedure might pass variables, literals, named constants, control values, and expressions in the argument list. The names often match in the calling and receiving argument lists, but not always.

Example

The module in Listing 13.1 doesn't contain all of its needed code, but only enough so that you can focus on the function's construction and operation. The variable r is received by reference, whereas v is received by value in the second procedure, RF (). If the RF () receiving function changes r, the CF () calling function's r is changed as well. If the RF () receiving function changes v, however, the CF() calling function's argument retains its original value.

Listing 13.1 Practice Passing and Receiving Values

Option Explicit

' Calling function is next

Private Function CF ()

  Dim r As Variant v As Variant   ' Declare local variables named r and v

  Dim i As Integer                ' to hold the return value of the function

  

  i = RF(r, v)          ' Call the function and pass r and v

                        ' i gets RF ()'s return value

End Function

' Receiving function is next

Private Function RF(r As Variant, ByVal v As Variant)

  ' Received r by reference and v by value

  r = 50        ' Changes r in both procedures

  v = 20        ' Changes v just here

  RF = r * i    ' Returns a value

End Function

Next Step

Think of how the InputBox() function works. To produce an input box, you issue a statement that looks something like this:

strUserName = InputBox("What is your name?", "Ask a name",

[ccc]"John Doe", 100, 50)

As you can now understand, the built-in functions work just like the functions you write. This statement calls the InputBox() function and passes five arguments to the function: three string literals and two numeric literals. The assignment can't take place until the InputBox() function completes, so the calling procedure is put on hold until users supply the input. After the InputBox() function completes, the user response-the string returned from InputBox()-must go somewhere. That somewhere is the variable named strUserName. You couldn't call InputBox() without supplying the capturing variable because Visual Basic would have no place to put the returned value.

InputBox() is just one of numerous Visual Basic built-in functions. Visual Basic supplies these built-in functions that not only work with I/O but also perform mathematical and string operations.

Summary

This lesson explained the significance of variable scope. You now understand the differences between local, module-level, and public variables. Keeping variables local-or perhaps at times on a module-level-helps maintain their integrity. Understanding when a variable is visible is the prelude to writing programs with many procedures. Although keeping variables local is suggested, local variables present a problem that you haven't, until now, had to address: They are visible only within the procedure in which you declare them. Therefore, you should keep all variables local for safety, but you need to transfer data between procedures only when needed and not all the time publicly.

When you pass and return variables between procedures, you ensure that only those procedures that need access to those variables have access. Also, you protect the variables from inadvertent change that can take place with too many public variables floating around the application.

Visual Basic lets you use the same public and local variable names in different procedures. Although you don't want to overdo this practice, using the same variable name for simple processing-such as in counters and for loop control-helps document your code and simplifies the number of variables you have to keep track of. If, however, you have a public variable and a local variable with the same name, the local variable always hides the public's value. Think of Visual Basic as always using the "most local" variable if two variables in the same module have the same name.

When you use local variables, your procedures must be able to communicate with each other. When one procedure contains data that another needs, pass the data argument from the calling procedure to the receiving procedure. The receiving procedure (if it's a function procedure) can return a single value back to the calling procedure. Normally, you pass arguments by reference, meaning that if the receiving procedure changes the arguments, the arguments are changed in the calling procedure also. If you pass arguments by value (by using ByVal), the receiving procedure can't change the calling procedure's arguments. Any changes made to the by-reference arguments inside the receiving procedure don't appear when the calling procedure regains control.

Hour 14, "Using the Supplied Functions," explores many of Visual Basic's built-in functions that will greatly simplify your work. Rather than write a common calculation or string-manipulation procedure, you can call one of the built-in functions that Visual Basic supplies. After the lesson, you'll be able to write your own functions and use Visual Basic's supplied functions to add power to your programs.

Hour 13 Quiz

  1. True or false: Every module contains a Declarations section.
  2. What kind of variable-local, module-level, or public-has the broadest scope?
  3. What kind of variable-local, module-level, or public-poses the most probable danger?
  4. How do name clashes occur?
  5. How many values can a Function procedure return?
  6. How many values can a Sub procedure return?
  7. If your program uses only local variables, name clashes don't occur. Why then must you be able to pass data between procedures?
  8. What are the two ways to pass values?
  9. True or false: The keyword ByRef is optional.
  10. 10. Suppose that a module contains a public variable named sngSales and a procedure within the same module creates a local variable named sngSales. Which variable-local or public-is changed by the following statement inside the procedure?
sngSales = curPrice * intQuantity

Hour 13 Homework Exercises

  1. By using Figure 13.2's outline box-notation, draw the following scenario: You're writing three modules. The first module, Mod1, contains a public Proc1 procedure with two local variables. The second of Mod1's procedures, pProc2, is private. The second module, Mod2, contains a module-level variable named m1 and a single procedure named Proc2a that contains a local variable named i. The third procedure declares a variable named s that's public to all the other modules and also contains one procedure named Proc3 that declares no variables.
  2. How can you change the code in Listing 13.2 so that v is passed by reference and r is passed by value?

Listing 13.2 Change the Passing Methods

Option Explicit

' Calling function is next

Private Function CF ()

  Dim r As Variant v As Variant   ' Declare local variables named r and v

  Dim i As Integer                ' to hold the return value of the function

  i = RF(r, v)          ' Call the function and pass r and v

                        ' i gets RF ()'s return value

End Function

' Receiving function is next

Private Function RF(r As Variant, ByVal v As Variant)

  ' Received r by reference and v by value

  r = 50        ' Changes r in both procedures

  v = 20        ' Changes v just here

  RF = r * i    ' Returns a value

End Function

  1. Write a module that contains two subroutine procedures. The first procedure asks for a name and the second prints the name. Don't use any module-level or public variables in the module.

© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.