A program function is slightly different from a subroutine in one important way: A function can return a value to the caller. Let's use the previous subroutine program from earlier in this chapter as a starting point to show the difference.
First, you need to change the btnSave object's Click() event code to the following:
Dim ItemPrice As Double, SalesTaxDue As Double ItemPrice = CDbl(txtCost.Text) SalesTaxDue = CalcSalesTax(ItemPrice) ' Call the function txtTax.Text = CStr(SalesTaxDue)
Note that the only change appears in the third line. You have removed SalesTaxDue from the parameter list and, instead, used it in an assignment statement after the call to CalcSalesTax() .
Now you need to change the code line for the CalcSalesTax() subroutine to the code shown in Listing 5.4.
Listing 5.4 Using CalcSalesTax() as a Function
Private Function CalcSalesTax(ByVal Price As Double) As Double ' Purpose: This subroutine calculates the sales tax ' that is to be collected for a given item. ' ' Arguments: ' Price the purchase price of the item ' SalesTax the sales tax amount to collect ' ' Return Value: ' double the sales tax due for this sale ' ' Caution: the calculation uses the symbolic constant ' SalesTaxRate, which holds the current sales ' tax rate. CalcSalesTax = Price * SalesTaxRate End Function
First, notice that the second word in the first line of Listing 5.4 is Function , not Sub , as before. This tells Visual Basic .NET that you are about to define a function rather than a subroutine.
Second, at the end of the first line, after the closing parenthesis, are the words As Double . This tells Visual Basic .NET that this function is designed to return a Double data type to the caller. This is what makes the function different: It returns a value to the caller. Listing 5.4 defines the function to return a Double data type. You can, of course, write functions that return any type of data you want. However, you must append As ??? to the end of each new function definition so Visual Basic .NET knows what the function is to return to the caller.
Third, notice that in the documentation for the function, several new lines that begin with Return Value: have been added. This provides the reader additional details about the Double data type that is being returned by this function. You should get in the habit of providing such documentation notes.
Fourth, a single statement forms the body of the function:
CalcSalesTax = Price * SalesTaxRate
This statement does two things. First, it calculates the sales tax that is due for this sale, as the product of Price multiplied by the SalesTaxRate . Using the values suggested in Figure 5.5, Price is 100 and SalesTaxRate is .05, yielding a tax due of 5. This product is then assigned into CalcSalesTax as though it were a variable, when it is actually the name of the function. All functions must use the following syntax in order to return a value to the caller:
FunctionName = ValueToBeReturned
This is the proper way to tell Visual Basic .NET what value is to be returned.
Fifth, notice that the last line of the function in Listing 5.4 is changed to read End Function rather than End Sub .
How does Visual Basic .NET actually get the value (that is, 5 ) back to the caller? It pushes the value 5 on the stack as a Double data type. After the last line in the CalcSalesTax() function executes, the stack looks as shown in Figure 5.16.
Figure 5.16. The new picture of the stack when CalcSalesTax() is called.
In fact, the last line in the program does calculate the sales tax due, and then it fakes an assignment into CalcSalesTax . The "assignment" really tells Visual Basic .NET to place the return value on the stack and return to the caller.
Now look at the program statement in the calling routine that set everything in motion in the first place:
SalesTaxDue = CalcSalesTax(ItemPrice) ' Call the subroutine
Because Visual Basic .NET knows that CalcSalesTax() returns a Double data type, it knows it must pop 8 bytes off the stack and shove those bytes into the memory address (that is, the lvalue ) for SalesTaxDue . If you use Figure 5.11 as a reference, you can see that Visual Basic .NET pops 8 bytes off the stack and puts them into the memory locations starting at address 6,000. This has the effect of changing the rvalue of SalesTaxDue to 5 . Think about it. It then pops the memory address for the next program instruction from the stack (50,001) and resumes program execution at that address. Pretty neat, huh?