Saturday, December 26, 2009

Procedures

Using Procedures in Visual Basic


You might not be aware of it, but you've been working with subs and functions for a while. Event procedures such as Click() and Load() are subs, and Visual Basic comes with many predefined functions built right into it, such as LoadPicture() and Len().

Visual Basic is a procedural language--that is, you can make blocks of code that can be referred to by a name. After a block of code has a name, it can be called and executed. In other words, you can 
write some lines of code, enclose them in a code block, give the block a name, and then call the block when you need it. It's almost like having a program within a program. These little programs that live within larger programs are called "functions" if they return a value and "subs" if they don't.

Programmers have written user-defined subs and functions for years. (In fact, the term "sub" is a shortened form of "subroutine" that gradually became its own word.) They make coding easier, faster, and more robust. Also, making your own subs and functions puts you on the road to writing encapsulated and reusable code. Encapsulation is simply the methods and properties of an object enclosed behind a public interface.


BUILT-IN FUNCTIONS

String Functions
Function Name: UCase
Function Description: Returns the String that is passed in all uppercase letters.
Common Uses: UCase can be used when the desired output is required to be in all uppercase letters. It is also commonly used when you wish to validate data entered by a user against a given string.
Syntax: String = UCase(String)
Examples:

UCase(“Input String”)  returns “INPUT STRING”
UCase(“all lowercase”) returns  “ALL LOWERCASE”


Previous Way of Coding Validation:
If (txtVote.Text = “Bush” Or txtVote.Text = “BUSH” Or _ txtVote.Text = “bush” Then ... 
If (UCase(txtVote.Text) = “BUSH”) Then ...
Function Name: LCase
Function Description: Returns the String that is passed in all lowercase letters.
Common Uses: LCase is very similar in use to UCase.
Syntax: String = LCase(String)
Examples:

UCase(“Input String”) returns “input string”
UCase(“all lowercase”)  returns “all lowercase”


Function Name: Trim
Function Description: Returns a String with the same content, except the leading and trailing spaces are removed.
Common Uses: Often when data is gathered, additional spaces may exist before the first noncharacter or after the last nonblank character. 
It is good practice to remove these so that data may be presented cleanly.
Syntax: String = Trim(String)
Examples:

Trim(“ InputString”)  returns “InputString”
Trim(“InputString ”) returns “InputString”


The following code will initialize two Strings. 
One will contain a String that has the leading and trailing spaces removed by the Trim function. 
It is displayed between two vertical bars so that it will be obvious that the spaces have been removed. 
The second String will be created in a similar manner; however, the spaces will not be removed.
Dim strTest As String
Dim strWithBlanks As String
Dim strBorder As String
Dim strTrimmedOutput As String
Dim strUnTrimmedOutput As String

strTest = " Hello " 'Two spaces before and after
strBorder = "|"
strTrimmedOutput = strBorder & Trim(strTest) & strBorder
strUnTrimmedOutput = strBorder & strTest & strBorder
MsgBox(strTrimmedOutput)
MsgBox(strUnTrimmedOutput)
Function Name: Space
Function Description: Returns a String containing the number of spaces indicated by the parameter.


Common Uses: Often you wish to add spaces to set the total length of a String to an exact size. 
This is often used when working with fixed-width data files.
Syntax: String = Space(Integer)
Examples:

Space(5)  retruns “     “
Space(10) returns “         “


Function Name: Len
Function Description: Returns the number of characters contained in a String
Common Uses: Len is used to determine the size of a String.
Syntax: Integer = Len(String)
Examples:

Len(“Inconceivable”)  returns 3
Len(“Iocaine Powder”) returns 14


Function Name: Left
Function Description: Returns the first N characters of a String where N is an Integer parameter indicating the number of characters to return. 
If N is greater than the number of characters in the String, then the String is returned. 
No extra spaces are added.
Common Uses: Often you are only concerned with the first few characters of a String. Left is a great way to look at only the beginning of a String.
Syntax: String = Microsoft.VisualBasic.Left(String, Integer)
Examples:

Left(“Beginning of String”, 5)  returns “Begin”
Left(“Beginning of String”, 2) returns  “Be”

Function Name: Right
Function Description: Returns the last N characters of a String where N is an Integer parameter indicating the number of characters to return. 
If N is greater than the number of characters in the String, then the String is returned. 
No extra spaces are added.
Common Uses: Often you are only concerned with the last few characters of a String. Right is a great way to look at only the end of a String.
Syntax: String = Right(String, Integer)
Examples:

Right(“Ending of String”, 5)   returns “tring”
Right(“Ending of String”, 2)  returns “ng”


Function Name: Mid
Function Description: Returns a specific number of characters of a String allowing the developer to indicate where to start and how many characters to return. 
The first parameter is the source String. 
The second is an Integer indicating the starting position to copy from. 
The third parameter is optional and indicates the number of characters to copy. 
If the third parameter is left out, all characters from the starting position are returned.
Common Uses: Often you wish to extract a portion of a String to use separately from the rest of the String. This is often the case when working with fixed-width data files.
Syntax: String = Mid(String, Starting Position, Optional Length)
Examples:
 
Mid(“This is the String”, 6, 2)   returns “is”
Mid(“This is the String”, 9, 3)  returns “the”


Function Name: InStr
Function Description: Returns the position of the first occurrence of a substring that is searched for in the String passed.


InStr(“ab ab ab”, “a”)  returns 1
InStr(“ab ab ab”, “c”)  returns 0



Common Uses: InStr can be used to tell us if a String has a certain substring contained within it. It operates much like searching a document for a word.

Syntax: Long = InStr(String to be Searched, Search String)


Examples:
 
InStr(“This is a very”, “is”)  retruns 3
InStr(“ab ab ab”, “ab”) returns 1

Conversion Functions


Function Name: Str
Function Description: Returns a String representation of the numeric value passed to it. 
By default it will place a single space in front of the first numeric character.
Syntax: String = Str(Numeric Value)
Examples:
'Proper conversion
Dim strDestination As String
Dim intSource As Integer
intSource = 1
strDestination = Str(intSource)
Function Name: Val
Function Description: Returns a numeric representation of the String value passed to it. 
Val will convert a String to a numeric until it reaches a character that is not a numeric value, a decimal point, or a white-space character. 
Once an unrecognizable character is read, conversion stops at that point.
Common Uses: Val is used much in the same manner as Str, except in the opposite direction.
Syntax: Numeric Value = Val(String)
Examples:

Val(“199.11”) retruns 199.11
Val(“ 199.11 “) retruns 199.11


Function Name: CDate

Function Description: Returns a Date representation of the String value passed to it. 
Common Uses: CDate is used when a Date representation is needed. 
Often a date can be stored in a String when it is gathered from a fixed-width or comma-delimited file. 
If proper operations are going to be performed on the date, then it is necessary to store it in its native format.
Syntax: Date = CDate(String)
Examples:
Dim dteToday As Date
Dim strToday As String
Dim strTomorrow As String
Dim dteTomorrow As Date
strToday = "September 30, 2001"
dteToday = CDate(strToday)
dteTomorrow = DateAdd(DateInterval.Day, 1, dteToday)
strTomorrow = CStr(dteTomorrow)
MsgBox(strTomorrow)

Mathematical Functions


Function Name: Int, Fix
Function Description: Returns the Integer portion of the numerical value passed to it.
Common Uses: Int or Fix are used when you wish to convert a numerical value to an integer without regard for the decimal value. It performs a truncation of the number.
Syntax: Integer = Int(Numerical Value)
  Integer = Fix(Numerical Value)

For e.g. Int(199.11) returns 199.

Miscellaneous Functions
Function Name: IsNumeric
Function Description: Returns True if the value passed to it evaluates to a numeric data type, otherwise it returns False.

Common Uses: IsNumeric can be used to verify that a value can be evaluated as a number. Instead of possibly getting either inaccurate results or a run-time error, by using IsNumeric, a proactive approach to error handling can be achieved.
Syntax: Boolean = IsNumeric(Expression)

For e.g. IsNumeric(“ABC”)

Function Name: IsDate
Function Description: Returns True if the value passed to it evaluates to a valid Date, otherwise it returns False.
Common Uses: IsDate can be used when you are about to convert a value to a Date representation. 
Instead of possibly getting either inaccurate results or a run-time error, by using IsDate, a proactive approach to error handling can be achieved.
Syntax: Boolean = IsDate(Expression)

for e.g. IsDate(“January 1, 2001”) 


Function Name: Today

Function Description: Returns the current system date.
Common Uses: Today can be used anytime the developer wishes to access the system date. 
While it is returned as a variant, it can be used as a native date format or converted to a String representation.
Syntax: Date = Today()
Examples:
'Code to display Yesterday’s Date in a MessageBox
Dim dteToday As Date
Dim dteYesterday As Date
Dim strYesterday As String

dteToday = Today()
dteYesterday = DateAdd(DateInterval.Day, -1, dteToday)
strYesterday = CStr(dteYesterday)
MsgBox(strYesterday)
Function Name: TimeOfDay
Function Description: Returns the current system time.
Common Uses: TimeOfDay can be used anytime the developer wishes to access the system time. 
While it is returned as a variant, it can be used as a native date format or converted to a String representation. 
You can store a Time in the DateTime data type.
Syntax: DateTime = TimeOfDay()
Examples:
'Code to display the time now in a MessageBox
Dim dteExactTime As DateTime
dteExactTime = TimeOfDay()
MsgBox(dteExactTime.ToString())
Function Name: Rnd
Function Description: Returns a pseudo random decimal number that is greater than or equal to 0 and less than 1. 
By passing Rnd an optional numeric parameter, you can further control the type of random number you generate.
Common Uses: Random numbers are required for a great many reasons. 
By combining the output of the Rnd function with some basic mathematics, random numbers can be generated within a given range.
Syntax: Variant = Rnd()
Examples:
Function Name: Rnd
Function Description: Returns a pseudo random decimal number that is greater than or equal to 0 and less than 1. 
By passing Rnd an optional numeric parameter, you can further control the type of random number you generate.
Common Uses: Random numbers are required for a great many reasons. 
By combining the output of the Rnd function with some basic mathematics, random numbers can be generated within a given range.
Syntax: Variant = Rnd()
Examples:

Function Name: Format
Function Description: Returns a String representation of the expression passed formatted according to instructions passed to it in the second parameter. Format may be used to improve the appearance of numbers, dates, times, or string values.
Common Uses: Format is used anytime the user needs to beautify the output of a value.Syntax: String = Format(Expression, String)

USER DEFINED FUNCTIONS / SUBROUTINES

Making code changes easily

Subs enable you to change code easily. If you have a body of code that you need to use repeatedly, put the code in a sub. Then, if you need to make a change in the code, simply go to the sub to make changes. If you don't put the code in a sub, you will have to go to every instance of the code in your program to make the required change. The more dispersed your code is, the harder it is to
make changes effectively and efficiently.


A sub is a procedure that executes the lines of code within its block but doesn't return a value. The syntax for a simple sub is as follows:

[Private|Public] Sub SubName()
.....lines of code
End Sub

In this syntax

[Private|Public] are the optional Visual Basic keywords that define the scope of the sub.

Sub is the Visual Basic keyword that denotes the type of procedure.

SubName is the name that you assign to your sub.

End Sub are the Visual Basic keywords that denote the end of a code block.

The following code snippet is an example of a simple sub:

Public Sub DataNotFound()
MsgBox "Data Not Found", vbInformation
End Sub

When you call this sub from other areas of your code, the sub displays a Windows message box with the string Data Not Found. The message box will display whatever text is used for the string constant.

Listing 3.1 shows the sub being called with the Visual Basic Call statement (line 2). Using the Call statement is optional. Although you can call a Sub by using only its name, using the Call keyword makes
your code more readable.


LISTING 3.1 18LIST01.TXT--Calling a Sub from an Event Procedure

01 Private Sub itmOpen_Click()
02 Call DataNotFound
03 End Sub


Making Subs by Using Add Procedure


You can add a sub to your project in two ways:

By writing the code directly into the General Declarations section of a form or module.

By using the Tools menu's Add Procedure option.


Enabling the Add Procedure menu item

For the Add Procedure menu item to be enabled, you must be in Code window view of the form or module into which you want to add the procedure.



Add a sub to your project with Add Procedure
1. From the Tools menu, choose Add Procedure to display the Add Procedure dialog.

2. Enter the sub Name
3. Click OK to add the sub's code block to the form or module (see Figure 18.2).


.

After you create the sub code block with the Add Procedure dialog, you add the procedure's code within the code block. Don't enter any code for the Sub after the End Sub keywords; this is illegal and
generates syntax errors when you compile the code.

Defining function

Making a Simple Function


A function is a procedure that executes lines of code and returns a value. The syntax for declaring a simple function is as follows:

[Private|Public] Function FunctionName() As DataType
...lines of code
FunctionName = ReturnValue
End Function

In this syntax

Private|Public are the optional Visual Basic keywords that define the scope of the function.

Function is the Visual Basic keyword that denotes the procedure is a function.

FunctionName is the name that you assign to your function.

As is the Visual Basic keyword that denotes a data type assignment.

DataType is the data type of the value that the function will return.

ReturnValue is the value that you pass back from the function by assigning it to the function's name. (This is very important!)

End Function are the Visual Basic keywords that denote the end of a code block.

The code snippet in Listing 3.2 shows a function, GetNumber(), the purpose of which is to return a number defined within the function itself.


LISTING 3.2 18LIST02.TXT--A Simple Function

01 Public Function GetNumber() As Integer
02 Dim a%
03 Dim b%
04 Dim c%
05 `Assign values to some variables
06 a% = 7
07 b% = 12
08
09 `Add them together
10 c% = a% + b%
11
12 `Pass the result out of the function by assigning
13 `it to the function name.
14 GetNumber = c%
15 End Function

You add a function to your project by using the same two methods that you use to add a sub--by putting it directly into the General Declarations section of the form or module or by using the Add
Procedure dialog. However, be advised that you have to manually add a little code when you add a function to your code by using the Add Procedure dialog

Passing Arguments into Subs and Functions


You can enhance the power and versatility of subs and functions by using arguments. An argument, also referred to as a parameter, is a variable that acts as a placeholder for a value that you'll pass into
the sub or function. You create arguments by placing them within the parentheses of the declaration statement of the sub or function. The following snippet of code shows the declaration for the function
EndDay(), which takes two arguments: one of type Integer and one of type String.

EndDay(NumOne As Integer, strName As String) As Integer

Using arguments greatly increases the reusability of your code. For example, imagine that in many places of your code you need to figure out the greater of two numbers. Every time you need to do this
calculation, you could write out the code, line for line, or you could write out a function that does this for you and then call the function when you need to do the calculation. The advantage of the latter
method is twofold:

One call satisfies many needs throughout your code.

If you need to enhance this functionality, you don't have to go through your code and make enhancements line by line; you simply go back to the function and make the changes within the function's code block.

Listing 3.3 shows the user-defined function GetGreaterNum(), which returns the greater of two numbers passed to it.


LISTING 3.3 18LIST03.TXT--A Simple Function That Takes Arguments

01 Public Function GetGreaterNum(NumOne As Integer, _
NumTwo As Integer) As Integer
02 `If the first number is greater than the second
03 If NumOne > NumTwo Then
04 `return the first number
05 GetGreaterNum = NumOne
06 Else
07 `if not, return the second number
08 GetGreaterNum = NumTwo
09 End If
10 End Function

Listing 3.4 shows the GetGreaterNum() function called from within a Click() event procedure.





LISTING 3.4 18LIST04.TXT--Using a Function Within an Event Procedure

0 1 Private Sub cmdGreaterNum_Click()
02 Dim i%
03 Dim j%
04 Dim RetVal%
05
06 `Get the input in txtNumOne and convert it to an integer
07 i% = CInt(txtNumOne.Text)
08
09 `Get the input in txtNumTwo and convert it to an integer
10 j% = CInt(txtNumTwo.Text)
11
12 RetVal% = GetGreaterNum(i%, j%)
13
14 `Take the result from the function, convert it to a
15 `string and assign it to the caption of the button.
16 cmdGreaterNum.Caption = CStr(RetVal%)
17 End Sub

It's very important when you use subs or functions that the argument's type and order match up. If you have a procedure that has three arguments of type Integer, you must pass in three integers; if you pass
in two Integers and a String, the compiler will throw an error. For example, if you have a function EndDay() declared as follows,

Public Function EndDay(iNum As Integer, dAccount _
As Double) As Double

and call the function by using the following line of code,

dMyResult = EndDay(6, "D56R")

this call generates an error. "D56R" is of type String, but the function is expecting the second argument to be of type Double. For this reason, a variable type declaration error appears.

Also, the argument count must match up. For example, you have a function declared as follows:

Public Function Bar(iNum as Integer, dNum as Double, _
strName as String) as Integer

and you call the function by using the following line of code:

iMyResult = Bar(6, 7)

This call also causes an error. The function expects three arguments, but you've passed in only two. Again, an error occurs.

It's possible to make an argument optional by using the Optional keyword before an argument when you declare the function. If there's an upper limit on the number of arguments that you're going to pass,
you should use the Optional keyword. These arguments must be declared as Variant.

Named Arguments

Using Named Arguments, Avoid problems with named arguments

Using named arguments enables you to avoid problems that might arise in function use because of the ordering of arguments.


You can use named arguments to make passing arguments to a procedure easier. A named argument is the literal name of an argument in a procedure. For example, if you have a function EndDay() that
takes two arguments, NumOne and NumTwo, of type Integer, you define it as follows:

EndDay(NumOne as Integer, NumTwo as Integer) as Integer

To pass a value to the function by using named arguments, you use the names of the arguments and assign values to them by using the := characters. Thus, to pass actual values into EndDay() by using
named arguments, you do the following:

X = EndDay(NumOne:=3, NumTwo:=4)

Exiting Subs and Functions


Sometimes you need to leave a procedure before it finishes. You do this by using the Exit keyword. Listing 3.5 shows the function ExitEarly(), which takes two arguments: an Integer used to determine the
upper limit of a loop and an Integer that flags the function when a special condition exists that requires the function to be exited early.


LISTING 3.5 18LIST05.TXT--Using the ExitEarly() Function

01 Public Function ExitEarly(iLimit As Integer, _
iFlag As Integer) As Integer
02 Dim i%
03 Dim Limit%
04 Dim Flag%
05
06 `Assign the limit argument to a local variable
07 Limit% = iLimit
08
09 `Assign the state argument to local variable
10 Flag%= iFlag
11
12 `Run a For...Next loop to Limit%
13 For i% = 0 To Limit%
14
15 `If the passed in state is one
16 If Flag% = 1 Then
17
18 `Check to see if i% equals half the value of
19 `the Limit variable
20 If i% = Limit% / 2 Then
21
22 `If it does, pass out the value of i%
23 `at that point
24 ExitEarly = i%
25
26 `Terminate the function; there is no
27 `reason to go on
28 Exit Function
29 End If
30 End If
31 Next i%
32
33 `If you made it this far, the flag variable does not
34 `equal one, so pass the value of i% out of the
35 `function by assigning the value of i% to the
36 `function name.
37 ExitEarly = i%
38
39 End Function

The ExitEarly() function works by taking the iLimit argument, assigning it to a variable local to the function (line 7) and then using that local variable to be the upper limit of a For...Next loop (line 13). The
function also takes the iFlag argument and assigns that variable to one that's also local to the function (line 10). Then the For...Next loop is run. Within the loop, if the value of the local Flag variable is 1 (line
16), an If...Then statement checks the value of the counting variable, i%, to see whether it's equal to half the value of the variable Limit (line 20). If it is, the value is assigned to the function's name (line 24) to
be passed back to the call, and the Exit keyword terminates the execution of the function (line 28). If the value of the local variable Flag is other than 1, the loop continues until it reaches its limit (line 31).
Then the value of i% is assigned to the function's name, and control is returned to the calling code (line 36).

When you create a user-defined function, the Visual Basic IDE treats it as though it were an intrinsic function. This means that the function is listed in the Object Browser and appears in the Quick Info window

Scope

Understanding Scope


Scope is the capability of two different variables to have the same name and maintain different values and lifetimes. Listing 3.6 shows two functions, EndDay() and Bar().


LISTING 3.6 LIST05.TXT--Two Variables with Different Scope

01 Public Function EndDay() as Integer
02 Dim x as Integer
03 Dim y as Integer
04
05 x = 2
06 y = 7
07 EndDay = x + y
08 End Function
09
10 Public Function Bar() as Integer
11 Dim x as Integer
12 Dim y as Integer
13
14 x = 12
15 y = 34
16 Bar = x * y
17 End Function

Notice that each function declares variables x and y. Also notice that those variables are assigned different values within each function (lines 5-6 and 14-15). This is possible because each set of variables exists only where it's created. In the function EndDay(), the variables x and y are created in lines 2 and 3. When the function ends in line 8, the variables are removed from memory and no longer exist. (This is known as going out of scope.) The same is true of the x and y variables in the Bar() function. Neither variable set can see the other. If you wanted to create variables i and j, the values of which could be seen by both functions, you would create the variables higher in scope in the General Declarations section of a form or module, using the Public or Private keywords when declaring them.


Documenting Subs and Functions

Although the EarlyExit()function is functionally adequate, it's difficult to implement from project to project. If other programmers wanted to use it, they would have to take more than a passing glance to figure out what the function is about and how to put it to good use. Proper documentation addresses this deficiency.

All subs and functions should have a header, a section of commented code that appears at the top of a code block. The header usually gives a synopsis of the procedure: the procedure name, a description of the arguments and return value if any, and some remarks as to what the procedure is about, with any special instructions. Also in the header is a history of when and who created the code. If any changes are made to the code, a description and date of the changes are added to the header. Finally, the header contains the appropriate copyright information.

You should also comment each task within the procedure. This saves time for others who will maintain your code. Commenting your code will save you a lot of effort when it comes time to revisit the code later. Listing 3.7 shows the ExitEarly() function commented in a professional manner (line numbering has been omitted for the sake of clarity).




LISTING 18.7 18LIST06.TXT--A Well-Documented Function

01 Public Function ExitEarly(iLimit As Integer, _
02 iFlag As Integer) As Integer
03 `****************************************
04 `Sub/Function: ExitEarly
05 `
06 `Arguments: iLimit The upper limit of the For..Next Loop
07 ` iFlag An integer indicating early exit from
08 ` the function. 1 = Exit.
09 ` Other values are ignored.
10 `
11 `Return: The value of the For...Next loop counter
12 `
13 `Remarks: This function is used to demonstrate the way
14 ` to use arguments within a function
15 `
16 `Programmer: Bob Reselman
17 `
18 `History: Created 4/20/98
19 `
20 `Copyright 1998, Macmillan Publishing
21 `****************************************
22
23 Dim i% `Counter variable
24 Dim Limit% `Internal variable for the upper limit of the
25 `For...Next loop
26 Dim Flag% `Internal variable for the exit flag
27
28 `Assign the limit argument to a local variable
29 Limit% = iLimit
30
31 `Assign the state argument to local variable
32 Flag% = iFlag
33
34 `Run a For...Next loop to Limit%
35 For i% = 0 To Limit%
36
37 `If the passed in state is one
38 If Flag% = 1 Then
39
40 `Check to see if i% equals half the value of
41 `the Limit variable
42 If i% = Limit% / 2 Then
43
44 `If it does, pass out the value of i%
45 `at that point
46 ExitEarly = i%
47
48 `Terminate the function; there is no reason
49 `to go on
50 Exit Function
51 End If
52 End If
53 Next i%
54
55 `If you made it this far, the state variable does not
56 `equal one, so pass the value of i% out of the function
57 `by assigning the value of i% to the function name.
58 ExitEarly = i%
59
60 End Function