Visual basic

The default value of the Explicit statement is On. This is also the recommended value,
and you should not make a habit of changing this setting. In the section ‘‘Why Declare
Variables?’’ later in this chapter, you will see an example of the pitfalls you’ll avoid by
declaring your variables. By setting the Explicit option to Off, you’re telling VB that youPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 56
56 CHAPTER 2 VARIABLES AND DATA TYPES
intend to use variables without declaring them. As a consequence, VB can’t make any assumption
about the variable’s type, so it uses a generic type of variable that can hold any type of
information. These variables are called Object variables, and they’re equivalent to the old
variants.
Figure 2.1
Setting the
variable-related options
on the project’s
Properties pages
Figure 2.2
Setting the
variable-related options
in the Visual Studio
Options dialog box
While the option Explicit is set to Off, every time Visual Basic runs into an undeclared variable
name, it creates a new variable on the spot and uses it. The new variable’s type is Object, the
generic data type that can accommodate all other data types. Using a new variable in your codePetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 57
VARIABLES 57
is equivalent to declaring it without type. Visual Basic adjusts its type according to the value you
assign to it. Create two variables, var1 and var2, by referencing themin your code with statements
like the following ones:
var1 = ”Thank you for using Fabulous Software”
var2 = 49.99
The var1 variable is a string variable, and var2 is a numeric one. You can verify this with the
GetType method, which returns a variable’s type. The following statements print the highlighted
types shown below each statement:
Debug.WriteLine ”Variable var1 is ” & var1.GetType().ToString
Variable var1 is System.String
Debug.WriteLine ”Variable var2 is ” & var2.GetType().ToString
Variable var2 is System.Double
Later in the same program, you can reverse the assignments:
var1 = 49.99
var2 = ”Thank you for using Fabulous Software”
If you execute the preceding statements again, you’ll see that the types of the variables
have changed. The var1 variable is now a Double, and var2 is a String. The type of a
generic variable is determined by the variable’s contents and it can change in the course
of the application. Of course, changing a variable’s type at runtime doesn’t come without
a performance penalty (a small one, but nevertheless some additional statements must be
executed).
Another related option is the Strict option, which is off by default. The Strict option tells
the compiler whether the variables should be strictly typed. A strictly typed variable must
be declared with a speci?c type and it can accept values of the same type only. With the Strict
option set to Off, you can use a string variable that holds a number in a numeric
calculation:
Dim a As String = ”25000”
Debug.WriteLine a / 2
The last statement will print the value 12500 in the Immediate window. Likewise, you can use
numeric variables in string calculations:
Dim a As Double = 31.03
a=a+”1”
If you turn the Strict option on by inserting the following statement at the beginning of the ?le,
you won’t be able to mix and match variable types:
Option Strict OnPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 58
58 CHAPTER 2 VARIABLES AND DATA TYPES
If you attempt to execute any of the last two code segments while the Strict option is on, the
compiler will underline a segment of the statement to indicate an error. If you rest the pointer over
the underlined segment of the code, the following error message will appear in a tip box:
Option strict disallows implicit conversions from String to Double
(or whatever type of conversion is implied by the statement).
When the Strict option is set to On, the compiler doesn’t disallow all implicit conversions
between data types. For example, it will allow you to assign the value of an integer to a Long,
but not the opposite. The Long value might exceed the range of values that can be represented by
an Integer variable. You will ?nd more information on implicit conversions in the section titled
‘‘Widening and Narrowing Conversions,’’ later in this chapter.
Object Variables
Variants — variables without a ?xed data type— were the bread and butter of VB programmers
up to version 6. Variants are the opposite of strictly typed variables: They can store all types of
values, from a single character to an object. If you’re starting with VB 2008, you should use strictly
typed variables. However, variants are a major part of the history of VB, and most applications
out there (the ones you may be called to maintain) use them. I will discuss variants brie?y in this
section and show you what was so good (and bad) about them.
Variants, or object variables, were themost ?exible data types because they could accommodate
all other types. A variable declared as Object (or a variable that hasn’t been declared at all) is
handled by Visual Basic according to the variable’s current contents. If you assign an integer value
to an object variable, Visual Basic treats it as an integer. If you assign a string to an object variable,
Visual Basic treats it as a string. Variants can also hold different data types in the course of the
same program. Visual Basic performs the necessary conversions for you.
To declare a variant, you can turn off the Strict option and use the Dim statement without
specifying a type, as follows:
Dim myVar
If you don’t want to turn off the Strict option (which isn’t recommended, anyway), you can
declare the variable with the Object data type:
Dim myVar As Object
Every time your code references a new variable, Visual Basic will create an object variable. For
example, if the variable validKey hasn’t been declared, when Visual Basic runs into the following
line, it will create a new object variable and assign the value 002-6abbgd to it:
validKey = ”002-6abbgd”
You can use object variables in both numeric and string calculations. Suppose that the variable
modemSpeed has been declared as Object with one of the following statements:
Dim modemSpeed ’ with Option Strict = Off
Dim modemSpeed As Object ’ with Option Strict = OnPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 59
VARIABLES 59
and later in your code you assign the following value to it:
modemSpeed = ”28.8”
The modemSpeed variable is a string variable that you can use in statements such as the
following:
MsgBox ”We suggest a ” & modemSpeed & ” modem.”
This statement displays the following message:
”We suggest a 28.8 modem.”
You can also treat the modemSpeed variable as a numeric value with the following
statement:
Debug.WriteLine ”A ” & modemSpeed & ” modem can transfer ” &
modemSpeed * 1024 /8&” bytes per second.”
This statement displays the following message:
”A 28.8 modem can transfer 3686.4 bytes per second.”
The ?rst instance of the modemSpeed variable in the preceding statement is treated
as a string because this is the variant’s type according to the assignment statement
(we assigned a string to it). The second instance, however, is treated as a number
(a single-precision number). Visual Basic converts it to a numeric value because it’s used
in a numeric calculation.
Another example of this behavior of variants can be seen in the following statements:
Dim I As Integer, S As String
I=10
S = ”11”
Debug.WriteLine(I + S)
Debug.WriteLine(I & S)
The ?rst WriteLine statement will display the numeric value 21, whereas the second statement
will print the string 1011. The plus operator (+) tells VB to add two values. In doing so, VB must
convert the two strings into numeric values and then add them. The concatenation operator (&)
tells VB to concatenate the two strings.
Visual Basic knows how to handle object variables in a way that makes sense. The result may
not be what you had in mind, but it certainly is dictated by common sense. If you really want to
concatenate the strings 10 and 11, you should use the & operator, which would tell Visual Basic
exactly what to do. Quite impressive, but for many programmers, this is a strange behavior that
can lead to subtle errors — and they avoid it. It’s up to you to decide whether to use variants and
how far you will go with them. Sure, you can perform tricks with variants, but you shouldn’t
overuse them to the point that others can’t read your code.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 60
60 CHAPTER 2 VARIABLES AND DATA TYPES
VariablesasObjects
Variables in VB 2008 are more than just names or placeholders for values. They’re intelligent
entities that can not only store but also process their values. I don’t mean to scare you, but I think
you should be told: VB 2008 variables are objects. And here’s why: A variable that holds dates is
declared as such with the following statement:
Dim expiration As Date
Then you can assign a date value to the expiration variable with a statement like this:
expiration = #1/1/2003#
So far, nothing out of the ordinary; this is how you use variables with any other language. In
addition to holding a date, however, the expiration variable can manipulate dates. The following
expression will return a new date that’s three years ahead of the date stored in the expiration
variable:
expiration.AddYears(3)
The new date can be assigned to another date variable:
Dim newExpiration As Date
newExpiration = expiration.AddYears(3)
AddYears is a method that knows how to add a number of years to a Date variable. There are
similarly named methods for adding months, days, and so on. In addition to methods, the Date
type exposes properties, such as the Month and Day properties, which return the date’s month
and day number, respectively. The keywords following the period after the variable’s name are
called methods and properties, just like the properties and methods of the controls you place on a
form to create your application’s visual interface. The methods and properties (or the members)
of a variable expose the functionality that’s built into the class representing the variable itself.
Without this built-in functionality, you’d have to write some serious code to extract the month
from a date variable, to add a number of days to a given date, to ?gure out whether a character is
a letter, a digit, or a punctuation symbol, and so on. Much of the functionality that you’ll need in
an application that manipulates dates, numbers, or text has already been built into the variables
themselves.
Don’t let the terminology scare you. Think of variables as placeholders for values and access
their functionality with expressions like the ones shown earlier. Start using variables to store
values and, if you need to process them, enter a variable’s name followed by a period to see a list
of the members it exposes. In most cases, you’ll be able to ?gure out what these members do by
just reading their names. I’ll come back to the concept of variables as objects, but I wanted to hit it
right off the bat. A more detailed discussion of the notion of variables as objects can be found in
Chapter 11, ‘‘Working with Objects,’’ which discusses objects in detail.
Programming languages can treat simple variables much more ef?ciently than objects. An
integer takes two bytes in memory, and the compiler will generate very ef?cient code to
manipulate an integer variable (add it to another numeric value, compare it to another integer,
and so on). If you declare an integer variable and use it in your code as such, Visual Studio doesn’t
create an object to represent this value. It creates a new variable for storing integers, like good oldPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 61
VARIABLES AS OBJECTS 61
BASIC. After you call one of the variable’s methods, the compiler emits code to create the actual
object. This process is called boxing and it introduces a small delay, which is truly insigni?cant
compared to the convenience of manipulating a variable through its methods.
As you’ve seen by now, variables are objects. This shouldn’t come as a surprise, but it’s an odd
concept for programmerswith no experience in object-oriented programming.We haven’t covered
objects and classes formally yet, but you have a good idea of what an object is. It’s an entity that
exposes some functionality by means of properties and methods. The TextBox control is an object
and it exposes the Text property, which allows you to read or set the text on the control. Any
name followed by a period and another name signi?es an object. The ‘‘other name’’ is a property
or method of the object.
Converting Variable Types
In many situations, you will need to convert variables from one type into another. Table 2.4 shows
the methods of the Convert class that perform data-type conversions.
Table 2.4: The Data-Type Conversion Methods of the Convert Class
Method Converts Its Argument To
ToBoolean Boolean
ToByte Byte
ToChar Unicode character
ToDateTime Date
ToDecimal Decimal
ToDouble Double
ToInt16 Short Integer (2-byte integer, Int16)
ToInt32 Integer (4-byte integer, Int32)
ToInt64 Long (8-byte integer, Int64)
ToSByte Signed Byte
CShort Short (2-byte integer, Int16)
ToSingle Single
ToString String
ToUInt16 Unsigned Integer (2-byte integer, Int16)
ToUInt32 Unsigned Integer (4-byte integer, Int32)
ToUInt64 Unsigned Long (8-byte integer, Int64)Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 62
62 CHAPTER 2 VARIABLES AND DATA TYPES
In addition to the methods of the Convert class, you can still use the data-conversion functions
of VB (CInt() to convert a numeric value to an Integer, CDbl() to convert a numeric value to
aDouble, CSng() to convert a numeric value to a Single, and so on), which you can look up in
the documentation. If you’re writing new applications in VB 2008, use the new Convert class to
convert between data types.
To convert the variable initialized as the following
Dim A As Integer
to a Double, use the ToDouble method of the Convert class:
Dim B As Double
B = Convert.ToDouble(A)
Suppose that you have declared two integers, as follows:
Dim A As Integer, B As Integer
A=23
B=7
The result of the operation A/B will be a Double value. The following statement
Debug.Write(A / B)
displays the value 3.28571428571429. The result is a Double value, which provides the
greatest possible accuracy. If you attempt to assign the result to a variable that hasn’t
been declared as Double, and the Strict option is on, then VB 2008 will generate an error
message. No other data type can accept this value without loss of accuracy. To store the
result to a Single variable, you must convert it explicitly with a statement like the
following:
Convert.ToSingle(A / B)
You can also use the DirectCast() function to convert a variable or expression from
one type to another. The DirectCast() function is identical to the CType() function.
Let’s say the variable A has been declared as String and holds the value 34.56. The
following statement converts the value of the A variable to a Decimal value and uses it
in a calculation:
Dim A As String = ”34.56”
Dim B As Double
B = DirectCast(A, Double) / 1.14
The conversion is necessary only if the Strict option is on, but it’s a good practice to perform
your conversions explicitly. The following section explains what might happen if your code relies
on implicit conversions.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 63
VARIABLES AS OBJECTS 63
Widening and Narrowing Conversions
In some situations, VB 2008 will convert data types automatically, but not always. Let’s say
you have declared and initialized two variables, an Integer and a Double, with the following
statements:
Dim count As Integer = 99
Dim pi As Double = 3.1415926535897931
If the Strict option is off and you assign the variable pi to the count variable, the count
variable’s new value will be 3. (The Double value was rounded to an Integer value, according
to the variable’s type.) Although this may be what you want, in most cases it’s an oversight that
will lead to incorrect results.
If the Strict option is on and you attempt to perform the same assignment, the compiler will
generate an error message to the effect that you can’t convert a Double to an Integer. The exact
message is Option Strict disallows implicit conversions from Double to Integer.
When the Strict option is on, VB 2008 will perform conversions that do not result in loss of
accuracy (precision) or magnitude. These conversions are called widening conversions.Whenyou
assign an Integer value to a Double variable, no accuracy or magnitude is lost. This is a widening
conversion, because it goes from a narrower to a wider type.
On the other hand, when you assign a Double value to an Integer variable, some accuracy is
lost (the decimal digits must be truncated). This is a narrowing conversion,becausewegofroma
data type that can represent a wider range of values to a data type that can represent a narrower
range of values.
Because you, the programmer, are in control, you might want to give up the accuracy —
presumably, it’s no longer needed. Table 2.5 summarizes the widening conversions that VB 2008
will perform for you automatically.
Table 2.5: VB 2008 Widening Conversions
Original Data Type Wider Data Type
Any type Object
Byte Short, Integer, Long, Decimal, Single, Double
Short Integer, Long, Decimal, Single, Double
Integer Long, Decimal, Single, Double
Long Decimal, Single, Double
Decimal Single, Double
Single Double
Double None
Char StringPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 64
64 CHAPTER 2 VARIABLES AND DATA TYPES
If the Strict option is on, the compiler will point out all the statements that may cause runtime
errors, and you can reevaluate your choice of variable types. You can also turn on the Strict option
temporarily to see the compiler’s warnings, and then turn it off again.
Formatting Numbers
So far, you’ve seen how to use the basic data types of the CLR. All data types expose a ToString
method, which returns the variable’s value (a number or date) as a string, so that it can be used
with other strings in your code. The ToString method formats numbers and dates in many
ways and it’s probably one of the most commonly needed methods. You can call the ToString
method without any arguments, as we have done so far, to convert any value to a string. The
ToString method, however, accepts an optional argument, which determines how the value will
be formatted as a string. For example, you can format a number as currency by pre?xing it with
the appropriate sign (for example, the dollar symbol) and displaying it to two decimal digits,
and you can display dates in many formats. Some reports require that negative amounts are
enclosed in parentheses. The ToString method allows you to display numbers and dates in any
way you wish.
Notice that ToString is a method, not a property. It returns a value that you can assign to a
string variable or pass as arguments to a function such as MsgBox(), but the original value is not
affected. The ToString method can also format a value if called with an optional argument:
ToString(formatString)
The formatString argument is a format speci?er (a string that speci?es the exact format
to be applied to the variable). This argument can be a speci?c character that corresponds to a
predetermined format (a standard format string, as it’s called) or a string of characters that
have special meaning in formatting numeric values (a picture format string). Use standard
format strings for the most common formatting options, and use picture strings to specify unusual
formatting requirements. To format the value 9959.95 as a dollar amount, you can use the
following standard currency:
Dim Amnt As Single = 9959.95
Dim strAmnt As String
strAmnt = Amnt.ToString(”C”)
Or use the following picture numeric format string:
strAmnt = Amnt.ToString(”$#,###.00”)
Both statements will format the value as $9,959.95. The ”C” argument in the ?rst example
means currency and formats the numeric value as currency. If you’re using a non-U.S. version of
Windows, the currency symbol will change accordingly. Use the Regional And Language Options
tool in the Control Panel to temporarily change the current culture to a European one, and the
amount will be formatted with the Euro sign.
The picture format string is made up of literals and characters that have special meaning
in formatting. The dollar sign has no special meaning and will appear as is. The # symbol is a
digit placeholder; all # symbols will be replaced by numeric digits, starting from the right. If the
number has fewer digits than speci?ed in the string, the extra symbols to the left will be ignored.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 65
VARIABLES AS OBJECTS 65
The comma tells the Format function to insert a comma between thousands. The period is the
decimal point, which is followed by two more digit placeholders. Unlike the # sign, the 0
is a special placeholder: If there are not enough digits in the number for all the zeros you’ve
speci?ed, a 0 will appear in the place of the missing digits. If the original value had been 9959.9,
for example, the last statement would have formatted it as $9,959.90. If you used the # placeholder
instead, the string returned by the Format method would have a single decimal digit.
Standard Numeric Format Strings
The ToString method of the numeric data types recognizes the standard numeric format strings
shown in Table 2.6.
Table 2.6: Standard Numeric Format Strings
Format Character Description Example
C or c Currency (12345.67).ToString(”C”) returns $12,345.67
D or d Decimal (123456789).ToString(”D”) returns 123456789.
It works with integer values only.
E or e Scienti?c format (12345.67).ToString(”E”) returns 1.234567E + 004
F or f Fixed-point format (12345.67).ToString(”F”) returns 12345.67
G or g General format Returns a value either in ?xed-point or scienti?c format
N or n Number format (12345.67).ToString(”N”) returns 12,345.67
P or p Percentage (0.12345).ToString(”N”) returns 12,35%
R or r Round-trip (1 / 3).ToString(”R”)returns 0.33333333333333331
(where the G speci?er would return a value with fewer
decimal digits: 0.333333333333333
X or x Hexadecimal format 250.ToString(”X”) returns FA
The format character can be followed by an integer. If present, the integer value speci?es the
number of decimal places that are displayed. The default accuracy is two decimal digits.
The C format string causes the ToString method to return a string representing the num-
ber as a currency value. An integer following the C determines the number of decimal digits
that are displayed. If no number is provided, two digits are shown after the decimal separator.
Assuming that the variable value has been declared as Decimal and its value is 5596, then the
expression value.ToString(”C”) will return the string $5,596.00.Ifthevalueofthevariable
were 5596.4499, then the expression value.ToString(”C3”) would return the string $5,596.450.
Notice that not all format strings apply to all data types. For example, only integer values can
be converted to hexadecimal format, and the D format string works with integer values only.
There are format strings and digits for dates too, and they’re discussed in Chapter 13, where I
will present the Date data type and related topics in detail.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 66
66 CHAPTER 2 VARIABLES AND DATA TYPES
Picture Numeric Format Strings
If the format characters listed in Table 2.6 are not adequate for the control you need over the
appearance of numeric values, you can provide your own picture format strings. Picture
format strings contain special characters that allow you to format your values exactly as you
like. Table 2.7 lists the picture formatting characters.
Table 2.7: Picture Numeric Format Strings
Format Character Description Effect
0 Display zero placeholder Results in a nonsigni?cant zero if a number has
fewer digits than there are zeros in the format
# Display digit placeholder Replaces the symbol with only signi?cant digits
. Decimal point Displays a period (.) character
, Group separator Separates number groups — for example, 1,000
% Percent notation Displays a % character
E + 0, E-0, e + 0, e-0 Exponent notation Formats the output of exponent notation
\ Literal character Used with traditional formatting sequences like
such as \n (newline)
‘‘’’ Literal string Displays any string within quotes or apostrophes
literally
; Section separator Speci?es different output if the numeric value to
be formatted is positive, negative, or zero
The following statements will print the highlighted values:
Dim Amount As Decimal = 42492.45
Debug.WriteLine(Amount.ToString(”$#,###.00”))
$42,492.45
Amount = 0.2678
Debug.WriteLine(Amount.ToString(”0.000”))
0.268
Amount = -24.95
Debug.WriteLine(Amount.ToString(”$#,###.00;($#,###.00)”))
($24.95)
User-De?ned Data Types
In the previous sections, we used variables to store individual values. As a matter of fact, most
programs store sets of data of different types. For example, a program for balancing your
checkbook must store several pieces of information for each check: the check’s number, amount,Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 67
VARIABLES AS OBJECTS 67
date, and so on. All these pieces of information are necessary to process the checks, and ideally,
they should be stored together.
You can create custom data types that are made up of multiple values using structures.AVB
structure allows you to combine multiple values of the basic data types and handle them as a
whole. For example, each check in a checkbook-balancing application is stored in a separate
structure (or record), as shown in Figure 2.3. When you recall a given check, you need all the
information stored in the structure.
Figure 2.3
Pictorial representation
of a structure
To de?ne a structure in VB 2008, use the Structure statement, which has the following syntax:
Structure structureName
Dim variable1 As varType
Dim variable2 As varType
...
Dim variablen As varType
End Structure
varType can be any of the data types supported by the CLR. The Dim statement can be replaced
by the Private or Public access modi?ers. For structures, Dim is equivalent to Public.
After this declaration, you have in essence created a new data type that you can use in your
application. structureName can be used anywhere you’d use any of the base types (Integers,
Doubles, and so on). You can declare variables of this type and manipulate them as you
manipulate all other variables (with a little extra typing). The declaration for the CheckRecord
structure shown in Figure 2.3 is as follows:
Structure CheckRecord
Dim CheckNumber As Integer
Dim CheckDate As Date
Dim CheckAmount As Single
Dim CheckPaidTo As String
End Structure
This declaration must appear outside any procedure; you can’t declare a Structure in a
subroutine or function. Once declared, The CheckRecord structure becomes a new data type for
your application.
To declare variables of this new type, use a statement such as this one:
Dim check1 As CheckRecord, check2 As CheckRecordPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 68
68 CHAPTER 2 VARIABLES AND DATA TYPES
To assign a value to one of these variables, you must separately assign a value to each one of its
components (they are called ?elds), which can be accessed by combining the name of the variable
and the name of a ?eld, separated by a period, as follows:
check1.CheckNumber = 275
Actually, as soon as you type the period following the variable’s name, a list of all
members to the CheckRecord structure will appear, as shown in Figure 2.4. Notice that the
structure supports a few members on its own. You didn’t write any code for the Equals,
GetType,and ToString members, but they’re standard members of any Structure object, and
you can use them in your code. Both the GetType and ToString methods will return a string
like ProjectName.FormName + CheckRecord. You can provide your own implementation of the
ToString method, which will return a more meaningful string:
Public Overrides Function ToString() As String
Return ”CHECK # ” & CheckNumber & ” FOR ” &
CheckAmount.ToString(”C”)
End Function
Figure 2.4
Variables of custom
types expose their mem-
bers as properties.
As you understand, structures are a lot like objects that expose their ?elds as properties and
then expose a few members of their own. The following statements initialize a CheckRecord
variable:
check2.CheckNumber = 275
check2.CheckDate = #09/12/2008#
check2.CheckAmount = 104.25
check2.CheckPaidTo = ”Gas Co.”Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 69
VARIABLES AS OBJECTS 69
You can also create arrays of structures with a declaration such as the following (arrays are
discussed later in this chapter):
Dim Checks(100) As CheckRecord
Each element in this array is a CheckRecord structure and it holds all the ?elds of a given check.
To access the ?elds of the third element of the array, use the following notation:
Checks(2).CheckNumber = 275
Checks(2).CheckDate = #09/12/2008#
Checks(2).CheckAmount = 104.25
Checks(2).CheckPaidTo = ”Gas Co.”
The Nothing Value
The Nothing value is used with object variables and indicates a variable that has not been
initialized. If you want to disassociate an object variable from the object it represents,
set it to Nothing. The following statements create an object variable that references a brush, uses
it, and then releases it:
Dim brush As SolidBrush
brush = New SolidBrush(Color.Blue)
{ use brush object to draw with}
brush = Nothing
The ?rst statement declares the brush variable.Atthispoint,the brush variable is Nothing.
The second statement initializes the brush variable with the appropriate constructor (the brush
is initialized to a speci?c color). After the execution of the second statement, the brush variable
actually represents an object you can draw with in blue. After using it to draw something, you can
release it by setting it to Nothing.
If you want to ?nd out whether an object variable has been initialized, use the Is or IsNot
operators, as shown in the following example:
Dim myPen As Pen
{ more statements here}
If myPen Is Nothing Then
myPen = New Pen(Color.Red)
End If
The variable myPen is initialized with the New constructor only if it hasn’t been initialized
already. If you want to release the myPen variable later in your code, you can set it to Nothing
with the assignment operator. When you compare an object to Nothing, however, you can’t use
the equals operator; you must use the Is and IsNot operators.
Examining Variable Types
Besides setting the types of variables and the functions for converting between types,
Visual Basic provides the GetType method, which returns a string with the variable’s typePetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 70
70 CHAPTER 2 VARIABLES AND DATA TYPES
(Int32, Decimal, and so on). Any variable exposes these methods automatically, and you can
call them like this:
Dim var As Double
Debug.WriteLine ”The variable’s type is ” & var.GetType.ToString
There’s also a GetType operator, which accepts as an argument a type and returns a Type
object for the speci?c data type. The GetType method and GetType operator are used mostly in If
structures, like the following one:
If var.GetType() Is GetType(Double) Then
{ code to handle a Double value}
End If
Notice that the code doesn’t reference data type names directly. Instead, it uses the value
returned by the GetType operator to retrieve the type of the class System.Double and then
compares this value to the variable’s type with the Is (or the IsNot)keyword.
Is It a Number, String, or Date?
Another set of Visual Basic functions returns variables’ data types, but not the exact type. They
return a True/False value indicating whether a variable holds a numeric value, a date or an array.
The following functions are used to validate user input, as well as data stored in ?les, before you
process them.
IsNumeric() Returns True if its argument is a number (Short, Integer, Long, Single,
Double, Decimal). Use this function to determine whether a variable holds a numeric value
before passing it to a procedure that expects a numeric value or before processing it as a
number. The following statements keep prompting the user with an InputBox for a numeric
value. The user must enter a numeric value or click the Cancel button to exit. As long as the
user enters non-numeric values, the Input box keeps popping up and prompting for a numeric
value:
Dim strAge as String = ””
Dim Age As Integer
While Not IsNumeric(strAge)
strAge = InputBox(”Please enter your age”)
End While
Age = Convert.ToInt16(strAge)
The variable strAge is initialized to a non-numeric value so that the While...End While loop
will be executed at least once.
IsDate() Returns True if its argument is a valid date (or time). The following expressions
return True because they all represent valid dates:
IsDate(#10/12/2010#)
IsDate(”10/12/2010”)
IsDate(”October 12, 2010”)Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 71
VARIABLES AS OBJECTS 71
If the date expression includes the day name, as in the following expression, the IsDate()
function will return False:
IsDate(”Sat. October 12, 2010”) ’ FALSE
IsArray() Returns True if its argument is an array.
Why Declare Variables?
Visual Basic never enforced variable declaration (and it still doesn’t), which was a good thing
for the beginner programmer. When you want to slap together a ‘‘quick-and-dirty’’ program,
the last thing you need is someone telling you to decide which variables you’re going to use
and to declare them before using them. This convenience, however, is a blessing in disguise
because most programmers accustomed to the free format of Visual Basic also carry their habits
of quick-and-dirty coding to large projects. When writing large applications, you will sooner or
later discover that variable declaration is a necessity. It will help you write clean, strongly typed
code and simplify debugging. Variable declaration eliminates the source of the most common and
totally unnecessary bugs.
Let’s examine the side effects of using undeclared variables in your application. To be able to
get by without declaring your variables, you must set the Explicit option to Off. Let’s assume that
you’re using the following statements to convert Euros to U.S. dollars:
Euro2USD = 1.462
USDollars = amount * Euro2USD
The?rsttimeyourcodereferstothe Euro2USD variable name, Visual Basic creates a new
variable and then uses it as if it were declared.
Suppose that the variable Euro2USD appears in many places in your application. If in one
of these places you type Euro2UDS, and the program doesn’t enforce variable declaration,
the compiler will create a new variable, assign it the value zero, and then use it. Any amount
converted with the Euro2UDS variable will be zero! If the application enforces variable declaration,
the compiler will complain (the Euro2UDS variable hasn’t been declared), and you will catch the
error right in the editor, as you type.
AVariable’sScope
In addition to its type, a variable also has a scope. The scope (or visibility) of a variable is the section
of the application that can see and manipulate the variable. If a variable is declared within a
procedure, only the code in the speci?c procedure has access to that variable; this variable doesn’t
exist for the rest of the application. When the variable’s scope is limited to a procedure, it’s called
local.
Suppose that you’re coding the Click event of a button to calculate the sumof all even numbers
in the range 0 to 100. One possible implementation is shown in Listing 2.4.
Listing 2.4: Summing Even Numbers
Private Sub Button1 Click(ByVal sender As Object,
ByVal e As System.EventArguments)Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 72
72 CHAPTER 2 VARIABLES AND DATA TYPES
Handles Button1.Click
Dim i As Integer
Dim Sum As Integer
For i = 0 to 100 Step 2
Sum = Sum + i
Next
MsgBox ”The sum is ” & Sum.ToString
End Sub
The variables i and Sum are local to the Button1 Click() procedure. If you attempt to set
the value of the Sum variable from within another procedure, Visual Basic will complain that the
variable hasn’t been declared. (Or, if you have turned off the Explicit option, it will create another
Sum variable, initialize it to zero, and then use it. But this won’t affect the variable Sum in the
Button1 Click() subroutine.) The Sum variable is said to have procedure-level scope: It’s visible
within the procedure and invisible outside the procedure.
Sometimes, however, you’ll need to use a variable with a broader scope; a variable that’s
available to all procedures within the same ?le. This variable, which must be declared outside
any procedure, is said to have a module-level scope. In principle, you could declare all variables
outside the procedures that use them, but this would lead to problems. Every procedure in the ?le
would have access to any variable, and you would need to be extremely careful not to change the
value of a variable without good reason. Variables that are needed by a single procedure (such as
loop counters) should be declared in that procedure.
Another type of scope is the block-level scope. Variables introduced in a block of code,
such as an If statement or a loop, are local to the block but invisible outside the block.
Let’s revise the previous code segment so that it calculates the sum of squares. To carry out
the calculation, we ?rst compute the square of each value and then sum the squares. The square
of each value is stored to a variable that won’t be used outside the loop, so we can de?ne
the sqrValue variable in the loop’s block and make it local to this speci?c loop, as shown in
Listing 2.5.
Listing 2.5: AVariableScopedinItsOwnBlock
Private Sub Button1 Click(ByVal sender As Object,
ByVal e As System.EventArguments)
Handles Button1.Click
Dim i, Sum As Integer
For i = 0 to 100 Step 2
Dim sqrValue As Integer
sqrValue =i*i
Sum = Sum + sqrValue
Next
MsgBox ”The sum of the squares is ” & Sum
End Sub
The sqrValue variable is not visible outside the block of the For...Next loop. If you attempt to
use it before the For statement or after the Next statement, VB will throw an exception.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 73
VARIABLES AS OBJECTS 73
The sqrValue variable maintains its value between iterations. The block-level variable is not
initialized at each iteration, even though there’s a Dim statement in the loop.
Finally, in some situations, the entire application must access a certain variable. In this case,
the variable must be declared as Public. Public variables have a global scope: They are visible from
any part of the application. To declare a public variable, use the Public statement in place of the
Dim statement. Moreover, you can’t declare public variables in a procedure. If you have multiple
forms in your application and you want the code in one form to see a certain variable in another
form, you can use the Public modi?er.
The Public keyword makes the variable available not only to the entire project, but also to
all projects that reference the current project. If you want your variables to be public within a
project (in other words, available to all procedures in any module in the project) but invisible
to referencing projects, use the Friend keyword in the declaration of the module. Variables you
want to use throughout your project, but to not become available to other projects that reference
this one, should be declared as Friend.
So, why do we need so many types of scope? You’ll develop a better understanding of
scope and which type of scope to use for each variable as you get involved in larger projects.
In general, you should try to limit the scope of your variables as much as possible. If all variables
were declared within procedures, you could use the same name for storing a temporary value
in each procedure and be sure that one procedure’s variables wouldn’t interfere with those of
another procedure, even if you use the same name.
A Variable’s Lifetime
In addition to type and scope, variables have a lifetime, which is the period for which they retain
their value. Variables declared as Public exist for the lifetime of the application. Local variables,
declared within procedures with the Dim or Private statement, live as long as the procedure.
When the procedure ?nishes, the local variables cease to exist, and the allocated memory is
returned to the system. Of course, the same procedure can be called again. In this case, the local
variables are re-created and initialized again. If a procedure calls another, its local variables retain
their values while the called procedure is running.
You also can force a local variable to preserve its value between procedure calls by using the
Static keyword. Suppose that the user of your application can enter numeric values at any time.
One of the tasks performed by the application is to track the average of the numeric values. Instead
of adding all the values each time the user adds a new value and dividing by the count, you can
keep a running total with the function RunningAvg(), which is shown in Listing 2.6.
Listing 2.6: Calculations with Global Variables
Function RunningAvg(ByVal newValue As Double) As Double
CurrentTotal = CurrentTotal + newValue
TotalItems = TotalItems + 1
RunningAvg = CurrentTotal / TotalItems
End Function
You must declare the variables CurrentTotal and TotalItems outside the function so that
their values are preserved between calls. Alternatively, you can declare them in the function with
the Static keyword, as shown in Listing 2.7.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 74
74 CHAPTER 2 VARIABLES AND DATA TYPES
Listing 2.7: Calculations with Local Static Variables
Function RunningAvg(ByVal newValue As Double) As Double
Static CurrentTotal As Double
Static TotalItems As Integer
CurrentTotal = CurrentTotal + newValue
TotalItems = TotalItems + 1
RunningAvg = CurrentTotal / TotalItems
End Function
The advantage of using static variables is that they help you minimize the number of total
variables in the application. All you need is the running average, which the RunningAvg()
function provides without making its variables visible to the rest of the application. Therefore,
you don’t risk changing the variables’ values from within other procedures.
Variables declared in a module outside any procedure take effect when the form is loaded and
cease to exist when the form is unloaded. If the form is loaded again, its variables are initialized as
if it’s being loaded for the ?rst time.
Variables are initialized when they’re declared, according to their type. Numeric variables
are initialized to zero, string variables are initialized to a blank string, and object variables are
initialized to Nothing.
Constants
Some variables don’t change value during the execution of a program. These variables are
constants that appear many times in your code. For instance, if your program does math
calculations, the value of pi (3.14159...) might appear many times. Instead of typing the value
3.14159 over and over again, you can de?ne a constant, name it pi, and use the name of the
constant in your code. The statement
circumference =2*pi* radius
is much easier to understand than the equivalent
circumference = 2 * 3.14159 * radius
You could declare pi as a variable, but constants are preferred for two reasons:
Constants don’t change value. This is a safety feature. After a constant has been declared,
you can’t change its value in subsequent statements, so you can be sure that the value speci?ed
in the constant’s declaration will take effect in the entire program.
Constants are processed faster than variables. When the program is running, the values
of constants don’t have to be looked up. The compiler substitutes constant names with their
values, and the program executes faster.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 75
ARRAYS 75
The manner in which you declare constants is similar to the manner in which you declare
variables, except that you use the Const keyword and in addition to supplying the constant’s
name, you must also supply a value, as follows:
Const constantname As type = value
Constants also have a scope and can be Public or Private. The constant pi, for instance, is
usually declared in a module as Public so that every procedure can access it:
Public Const pi As Double = 3.14159265358979
The name of the constant follows the same rules as variable names. The constant’s value is a
literal value or a simple expression composed of numeric or string constants and operators. You
can’t use functions in declaring constants. By the way, the speci?c value I used for this example
need not be stored in a constant. Use the pi member of the Math class instead (Math.pi).
Constants can be strings, too, like these:
Const ExpDate = #31/12/1997#
Const ValidKey = ”A567dfe”
Arrays
A standard structure for storing data in any programming language is the array. Whereas
individual variables can hold single entities, such as one number, one date, or one string, arrays
can hold sets of data of the same type (a set of numbers, a series of dates, and so on). An array has
a name, as does a variable, and the values stored in it can be accessed by an index.
For example, you could use the variable Salary to store a person’s salary:
Salary = 34000
But what if you wanted to store the salaries of 16 employees? You could either declare 16
variables — Salary1, Salary2,andsoonupto Salary16 — or declare an array with 16 elements.
An array is similar to a variable: It has a name and multiple values. Each value
is identi?ed by an index (an integer value) that follows the array’s name in parentheses. Each
different value is an element of the array. If the array Salaries holds the salaries of 16 employ-
ees, the element Salaries(0) holds the salary of the ?rst employee, the element Salaries(1)
holds the salary of the second employee, and so on up to the element Salaries(15).
Declaring Arrays
Unlike simple variables, arrays must be declared with the Dim (or Public) statement followed by
the name of the array and the index of the last element in the array in parentheses— for example:
Dim Salary(15) As IntegerPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 76
76 CHAPTER 2 VARIABLES AND DATA TYPES
Salary is the name of an array that holds 16 values (the salaries of the 16 employees)
with indices ranging from 0 to 15. Salary(0) is the ?rst person’s salary, Salary(1) the second
person’s salary, and so on. All you have to do is remember who corresponds to each salary, but
even this data can be handled by another array. To do this, you’d declare another array of 16
elements:
Dim Names(15) As String
Then assign values to the elements of both arrays:
Names(0) = ”Joe Doe”
Salary(0) = 34000
Names(1) = ”Beth York”
Salary(1) = 62000
...
Names(15) = ”Peter Smack”
Salary(15) = 10300
This structure is more compact and more convenient than having to hard-code the names of
employees and their salaries in variables.
All elements in an array have the same data type. Of course, when the data type is Object,
the individual elements can contain different kinds of data (objects, strings, numbers, and
so on).
Arrays, like variables, are not limited to the basic data types. You can declare arrays that hold
any type of data, including objects. The following array holds colors, which can be used later in
the code as arguments to the various functions that draw shapes:
Dim colors(2) As Color
colors(0) = Color.BurlyWood
colors(1) = Color.AliceBlue
colors(2) = Color.Sienna
The Color class represents colors, and among the properties it exposes are the names of the
colors it recognizes.
A better technique for storing names and salaries is to create a structure and then declare an
array of this type. The following structure holds names and salaries:
Structure Employee
Dim Name As String
Dim Salary As Decimal
End Structure
Insert this declaration in a form’s code ?le, outside any procedure. Then create an array of the
Employee type:
Dim Emps(15) As EmployeePetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 77
ARRAYS 77
Each element in the Emps array exposes two ?elds, and you can assign values to them by using
statements such as the following:
Emps(2).Name = ”Beth York”
Emps(2).Salary = 62000
The advantage of using an array of structures instead of multiple arrays is that the related
information will always be located under the same index. The code is more compact, and you
need not maintain multiple arrays.
Initializing Arrays
Just as you can initialize variables in the same line in which you declare them, you can initialize
arrays, too, with the following constructor (an array initializer, as it’s called):
Dim arrayname() As type = {entry0, entry1, ... entryN}
Here’s an example that initializes an array of strings:
Dim Names() As String = {”Joe Doe”, ”Peter Smack”}
This statement is equivalent to the following statements, which declare an array with two
elements and then set their values:
Dim Names(1) As String
Names(0) = ”Joe Doe”
Names(1) = ”Peter Smack”
The number of elements in the curly brackets following the array’s declaration determines the
dimensions of the array, and you can’t add new elements to the array without resizing it. If you
need to resize the array in your code dynamically, you must use the ReDim statement, as described
in the section called ‘‘Dynamic Arrays,’’ later in this chapter. However, you can change the value
of the existing elements at will, as you would with any other array.
Array Limits
The ?rst element of an array has index 0. The number that appears in parentheses in the Dim
statement is one fewer than the array’s total capacity and is the array’s upper limit (or upper
bound). The index of the last element of an array (its upper bound) is given by the method
GetUpperBound, which accepts as an argument the dimension of the array and returns the
upper bound for this dimension. The arrays we examined so far are one-dimensional and the
argument to be passed to the GetUpperBound method is the value 0. The total number of
elements in the array is given by the method GetLength, which also accepts a dimension
as an argument. The upper bound of the following array is 19, and the capacity of the array is
20 elements:
Dim Names(19) As IntegerPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 78
78 CHAPTER 2 VARIABLES AND DATA TYPES
The ?rst element is Names(0), and the last is Names(19). If you execute the following
statements, the highlighted values will appear in the Output window:
Debug.WriteLine(Names.GetLowerBound(0))
0
Debug.WriteLine(Names.GetUpperBound(0))
19
To assign a value to the ?rst and last element of the Names array, use the following
statements:
Names(0) = ”First entry”
Names(19) = ”Last entry”
If you want to iterate through the array’s elements, use a loop like the following one:
Dim i As Integer, myArray(19) As Integer
Fori=0To myArray.GetUpperBound(0)
myArray(i) = i * 1000
Next
The actual number of elements in an array is given by the expression
myArray.GetUpperBound(0) + 1. You can also use the array’s Length property to retrieve the
count of elements. The following statement will print the number of elements in the array myArray
in the Output window:
Debug.WriteLine(myArray.Length)
Still confused with the zero-indexing scheme, the count of elements, and the index of the
last element in the array? You can make the array a little larger than it needs to be and
ignorethe?rstelement.Justmakesurethat you never use the zero element in your
code — don’t store a value in the element Array(0), and you can then ignore this element.
To get 20 elements, declare an array with 21 elements as Dim MyArray(20) As type and
then ignore the ?rst element.
Multidimensional Arrays
One-dimensional arrays, such as those presented so far, are good for storing long sequences of
one-dimensional data (such as names or temperatures). But how would you store a list of cities and
their average temperatures in an array? Or names and scores; years and pro?ts; or data with more
than two dimensions, such as products, prices, and units in stock? In some situations, you will
want to store sequences of multidimensional data. You can store the same data more conveniently
in an array of as many dimensions as needed.
Figure 2.5 shows two one-dimensional arrays — one of them with city names, the other with
temperatures. The name of the third city would be City(2), and its temperature would be
Temperature(2).
A two-dimensional array has two indices: The ?rst identi?es the row (the order of the
city in the array), and the second identi?es the column (city or temperature). To access the namePetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 79
ARRAYS 79
and temperature of the third city in the two-dimensional array, use the following
indices:
Temperatures(2, 0) ’ is the third city’s name
Temperatures(2, 1) ’ is the third city’s average temperature
Figure 2.5
Two one-dimensional
arrays and the equiv-
alent two-dimensional
array
The bene?t of using multidimensional arrays is that they’re conceptually easier to manage.
Suppose that you’re writing a game and want to track the positions of certain pieces on a board.
Each square on the board is identi?ed by two numbers: its horizontal and vertical coordinates.
The obvious structure for tracking the board’s squares is a two-dimensional array, in which the
?rst index corresponds to the row number, and the second corresponds to the column number.
The array could be declared as follows:
Dim Board(9, 9) As Integer
When a piece is moved from the square in the ?rst row and ?rst column to the square in the
third row and ?fth column, you assign the value 0 to the element that corresponds to the initial
position:
Board(0, 0) = 0
And you assign 1 to the square to which it was moved to indicate the new state of the
board:
Board(2, 4) = 1
To ?nd out whether a piece is on the top-left square, you’d use the following statement:
If Board(0, 0) = 1 Then
{ piece found}
Else
{ empty square}
End IfPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 80
80 CHAPTER 2 VARIABLES AND DATA TYPES
This notation can be extended to more than two dimensions. The following statement creates
an array with 1,000 elements (10 by 10 by 10):
Dim Matrix(9, 9, 9)
You can think of a three-dimensional array as a cube made up of overlaid two-dimensional
arrays, such as the one shown in Figure 2.6.
Figure 2.6
Pictorial representa-
tions of one-, two-, and
three-dimensional arrays
It is possible to initialize a multidimensional array with a single statement, just as you do with
a one-dimensional array. You must insert enough commas in the parentheses following the array
name to indicate the array’s rank. The following statements initialize a two-dimensional array and
then print a couple of its elements:
Dim a(,) As Integer = {{10, 20, 30}, {11, 21, 31}, {12, 22, 32}}
Console.WriteLine(a(0, 1)) ’ will print 20
Console.WriteLine(a(2, 2)) ’ will print 32
You should break the line that initializes the dimensions of the array into multiple lines to
make your code easier to read. Just insert the line continuation character at the end of each
continued line:
Dim a(,) As Integer = {{10, 20, 30},
{11, 21, 31},
{12, 22, 32}}
If the array has more than one dimension, you can ?nd out the number of dimensions with
the Array.Rank property. Let’s say you have declared an array for storing names and salaries by
using the following statements:
Dim Employees(1,99) As Employee
To ?nd out the number of dimensions, use the following statement:
Employees.RankPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 81
ARRAYS 81
When using the Length property to ?nd out the number of elements in a multidimensional
array, you will get back the total number of elements in the array (2 × 100 for our example). To
?nd out the number of elements in a speci?c dimension, use the GetLength method, passing as an
argument a speci?c dimension. The following expressions will return the number of elements in
the two dimensions of the array:
Debug.WriteLine(Employees.GetLength(0))
2
Debug.WriteLine(Employees.GetLength(1))
100
Because the index of the ?rst array element is zero, the index of the last element is the length
of the array minus 1. Let’s say you have declared an array with the following statement to store
player statistics for 15 players, and there are ?ve values per player:
Dim Statistics(14, 4) As Integer
The following statements will return the highlighted values shown beneath them:
Debug.WriteLine(Statistics.Rank)
2 ’ dimensions in array
Debug.WriteLine(Statistics.Length)
75 ’ total elements in array
Debug.WriteLine(Statistics.GetLength(0))
15 ’ elements in first dimension
Debug.WriteLine(Statistics.GetLength(1))
5 ’ elements in second dimension
Debug.WriteLine(Statistics.GetUpperBound(0))
14 ’ last index in the first dimension
Debug.WriteLine(Statistics.GetUpperBound(1))
4 ’ last index in the second dimension
Multidimensional arrays are becoming obsolete because arrays (and other collections) of
custom structures and objects are more ?exible and convenient.
Dynamic Arrays
Sometimes you may not know how large to make an array. Instead of making it large enough
to hold the (anticipated) maximum number of data (which means that, on the average, part of
the array may be empty), you can declare a dynamic array. The size of a dynamic array can vary
during the course of the program. Or you might need an array until the user has entered a bunch
of data, and the application has processed it and displayed the results. Why keep all the data in
memory when it is no longer needed? With a dynamic array, you can discard the data and return
the resources it occupied to the system.
To create a dynamic array, declare it as usual with the Dim statement (or Public or Private),
but don’t specify its dimensions:
Dim DynArray() As IntegerPetroutsos c02.tex V2 - 01/28/2008 12:12pm Page 82
82 CHAPTER 2 VARIABLES AND DATA TYPES
Later in the program, when you know how many elements you want to store in the array, use
the ReDim statement to redimension the array, this time to its actual size. In the following example,
UserCount is a user-entered value:
ReDim DynArray(UserCount)
The ReDim statement can appear only in a procedure. Unlike the Dim statement, ReDim is
executable— it forces the application to carry out an action at runtime. Dim statements aren’t
executable, and they can appear outside procedures.
A dynamic array also can be redimensioned to multiple dimensions. Declare it with the Dim
statement outside any procedure, as follows:
Dim Matrix() As Double
Then use the ReDim statement in a procedure to declare a three-dimensional array:
ReDim Matrix(9, 9, 9)
Note that the ReDim statement can’t change the type of the array — that’s why the As clause
is missing from the ReDim statement. Moreover, subsequent ReDim statements can change the
bounds of the array Matrix but not the number of its dimensions. For example, you can’t use the
statement ReDim Matrix(99, 99) laterinyourcode.
The Preserve Keyword
Each time you execute the ReDim statement, all the values currently stored in the array are lost.
Visual Basic resets the values of the elements as if the array were just declared (it resets numeric
elements to zero and String elements to empty strings.) You can, however, change the size of the
array without losing its data. The ReDim statement recognizes the Preserve keyword, which forces
it to resize the array without discarding the existing data. For example, you can enlarge an array
by one element without losing the values of the existing elements:
ReDim Preserve DynamicArray(DynArray.GetUpperBound(0) + 1)
If the array DynamicArray held 12 elements, this statement would add one element to the array:
the element DynamicArray(12). The values of the elements with indices 0 through 11 wouldn’t
change.
The BottomLine
Declare and use variables. Programs use variables to store information during
their execution, and different types of information are stored in variables of different types.
Dates, for example, are stored in variables of the Date type, while text is stored in variables
of the String type. The various data types expose a lot of functionality that’s speci?c to a data
type; the methods provided by each data type are listed in the IntelliSense box.Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 83
THE BOTTOM LINE 83
Master It How would you declare and initialize a few variables?
Master It Explain brie?y the Explicit, Strict, and Infer options.
Use the native data types. The CLR recognized the following data types, which you can
use in your code to declare variables: Strings, Numeric types, Date and time types, Boolean
data type.
All other variables, or variables that are declared without a type, are Object variables and can
store any data type, or any object.
Master It How will the compiler treat the following statement?
Dim amount = 32
Create custom data types. Practical applications need to store and manipulate multiple
data items, not just integers and strings. To maintain information about people, we
need to store each person’s name, date of birth, address, and so on. Products have a
name, a description, a price, and other related items. To represent such entities in our code,
we use structures, which hold many pieces of information about a speci?c entity
together.
Master It Create a structure for storing products and populate it with data.
Use arrays. Arrays are structures for storing sets of data, as opposed to single-valued
variables.
Master It How would you declare an array for storing 12 names and another one for
storing 100 names and Social Security numbers?Petroutsos c02.tex V2 - 01/28/2008 12:12pm Page 84Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 85
Chapter 3
Programming Fundamentals
The one thing you should have learned about programming in Visual Basic so far is that an appli-
cation is made up of small, self-contained segments. The code you write isn’t a monolithic listing;
it’s made up of small segments called procedures, and you work on one procedure at a time.
The two types of procedures supported by Visual Basic are the topics we’ll explore in this
chapter: subroutines and functions — the building blocks of your applications.We’ll discuss them
in detail: how to call them with arguments and how to retrieve the results returned by the func-
tions. You’ll learn how to use the built-in functions that come with the language, as well as how to
write your own subroutines and functions.
The statements that make up the core of the language are actually very few. The ?exibility of
any programming language is based on its capacity to alter the sequence in which the statements
are executed through a set of so-called ?ow-control statements. These are the statements that
literally make decisions and react differently depending on the data, user actions, or external
conditions. Among other topics, in this chapter you’ll learn how to do the following:
? Use Visual Basic’s ?ow-control statements
? Write subroutines and functions
? Pass arguments to subroutines and functions
Flow-Control Statements
What makes programming languages so ?exible and capable of handling every situation and pro-
gramming challenge with a relatively small set of commands is their capability to examine external
or internal conditions and act accordingly. Programs aren’tmonolithic sets of commands that carry
out the same calculations every time they are executed; this is what calculators (and extremely sim-
ple programs) do. Instead, they adjust their behavior depending on the data supplied; on external
conditions, such as a mouse click or the existence of a peripheral; even on abnormal conditions
generated by the program itself.
In effect, the statements discussed in the ?rst half of this chapter are what programming is all
about. Without the capability to control the ?ow of the program, computers would just be bulky
calculators. You have seen how to use the If statement to alter the ?ow of execution in previous
chapters, and I assume you’re somewhat familiar with these kinds of statements. In this section,
you’ll ?nd a formal discussion of ?ow-control statements. These statements are grouped into two
major categories: decision statements and looping statements.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 86
86 CHAPTER 3 PROGRAMMING FUNDAMENTALS
Decision Statements
Applications need a mechanism to test conditions and take a different course of action depending
on the outcome of the test. Visual Basic provides three such decision,or conditional, statements:
? If...Then
? If...Then...Else
? Select Case
If...Then
The If...Then statement tests an expression, which is known as a condition. If the condition is
True, the program executes the statement(s) that follow. The If...Then statement can have a
single-line or a multiple-line syntax. To execute one statement conditionally, use the single-line
syntax as follows:
If condition Then statement
Conditions are logical expressions that evaluate to a True/False value and they usually contain
comparison operators— equals (=), different (<>), less than (<), greater than (>), less than or
equal to (<=), and so on — and logical operators: And, Or, Xor,and Not. Here are a few examples
of valid conditions:
If (age1 < age2) And (age1 > 12) Then ...
If score1 = score2 Then ...
The parentheses are not really needed in the ?rst sample expression, but they make the code
a little easier to read. Sometimes parentheses are mandatory, to specify the order in which the
expression’s parts will be evaluated, just like math formulae may require parentheses to indicate
the precedence of calculations. You can also execute multiple statements by separating them
with colons:
If condition Then statement: statement: statement
Here’s an example of a single-line If statement:
expDate = expDate + 1
If expdate.Month > 12 Then expYear = expYear + 1: expMonth = 1
You can break this statement into multiple lines by using the multiline syntax of the If state-
ment, which delimits the statements to be executed conditionally with the End If statement, as
shown here:
If expDate.Month > 12 Then
expYear = expYear + 1
expMonth = 1
End If
The Month property of the Date type returns the month of the date to which it’s applied as a
numeric value. Most VB developers prefer the multiple-line syntax of the If statement, even ifPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 87
FLOW-CONTROL STATEMENTS 87
it contains a single statement. The block of statements between the Then and End If keywords
form the body of the conditional statement, and you can have as many statements in the body
as needed.
Many control properties are Boolean values, which evaluate to a True/False value. Let’s say
that your interface contains a CheckBox control and you want to set its caption to On or Off
depending on whether it’s selected at the time. Here’s an If statement that changes the caption of
the CheckBox:
If CheckBox1.Checked Then
CheckBox1.Text = ”ON”
Else
CheckBox1.Text = ”OFF”
End If
This statement changes the caption of the CheckBox all right, but when should it be executed?
Insert the statement in the CheckBox control’s CheckedChanged event handler, which is ?red every
time the control’s check mark is turned on or off, whether because of a user action on the interface
or from within your code.
The expressions can get quite complicated. The following expression evaluates to True if the
date1 variable represents a date earlier than the year 2008 and either one of the score1 and score2
variables exceeds 90:
If (date1 < #1/1/2008) And (score1 < 90 Or score2 < 90) Then
‘ statements
End If
The parentheses around the last part of the comparison are mandatory, because we want the
compiler to perform the following comparison ?rst:
score1 < 90 Or score2 < 90
If either variable exceeds 90, the preceding expression evaluates to True and the initial condi-
tion is reduced to the following:
If (date1 < #1/1/2008) And (True) Then
The compiler will evaluate the ?rst part of the expression (it will compare two dates) and
?nally it will combine two Boolean values with the And operator: if both values are True, the entire
condition is True; otherwise, it’s False. If you didn’t use parentheses, the compiler would evaluate
the three parts of the expression:
expression1: date1 < #1/1/2008#
expression2: score1 < 90
expression3: score2 < 90
Then it would combine expression1 with expression2 using the And operator, and ?nally it
would combine the result with expression3 using the OR operator. If score2 were less than 90,
the entire expression would evaluate to True, regardless of the value of the date1 variable.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 88
88 CHAPTER 3 PROGRAMMING FUNDAMENTALS
If...Then...Else
A variation of the If...Then statement is the If...Then...Else statement, which executes one
block of statements if the condition is True and another block of statements if the condition is
False. The syntax of the If...Then...Else statement is as follows:
If condition Then
statementblock1
Else
statementblock2
End If
Visual Basic evaluates the condition; if it’s True, VB executes the ?rst block of statements and
then jumps to the statement following the End If statement. If the condition is False, Visual Basic
ignores the ?rst block of statements and executes the block following the Else keyword.
A third variation of the If...Then...Else statement uses several conditions, with the ElseIf
keyword:
If condition1 Then
statementblock1
ElseIf condition2 Then
statementblock2
ElseIf condition3 Then
statementblock3
Else
statementblock4
End If
You can have any number of ElseIf clauses. The conditions are evaluated from the top, and if
one of them is True, the corresponding block of statements is executed. The Else clause, which is
optional, will be executed if none of the previous expressions is True. Listing 3.1 is an example of
an If statement with ElseIf clauses.
Listing 3.1: Multiple ElseIf Statements
score = InputBox(”Enter score”)
If score < 50 Then
Result = ”Failed”
ElseIf score < 75 Then
Result = ”Pass”
ElseIf score < 90 Then
Result = ”Very Good”
Else
Result = ”Excellent”
End If
MsgBox ResultPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 89
FLOW-CONTROL STATEMENTS 89
Multiple If...Then Structures versus ElseIf
Notice that after a True condition is found, Visual Basic executes the associated statements and skips
the remaining clauses. It continues executing the program with the statement immediately after End
If. All following ElseIf clauses are skipped, and the code runs a bit faster. That’s why you should
prefer the complicated structure with the ElseIf statements used in Listing 3.1 to this equivalent
series of simple If statements:
If score < 50 Then
Result = ”Failed”
End If
If score < 75 And score >= 50 Then
Result = ”Pass”
End If
If score < 90 And score > =75 Then
Result = ”Very Good”
End If
If score >= 90 Then
Result = ”Excellent”
End If
With the multiple If statements, the compiler will generate code that evaluates all the conditions,
even if the score is less than 50.
The order of the comparisons is vital when you’re using multiple ElseIf statements. Had
you written the previous code segment with the ?rst two conditions switched, like the following
segment, the results would be quite unexpected:
If score < 75 Then
Result = ”Pass”
ElseIf score < 50 Then
Result = ”Failed”
ElseIf score < 90 Then
Result = ”Very Good”
Else
Result = ”Excellent”
End If
Let’s assume that score is 49. The code would compare the score variable to the value 75.
Because 49 is less than 75, it would assign the value Pass to the variable Result,andthenitwould
skip the remaining clauses. Thus, a student who scored 49 would have passed the test! So be
extremely careful and test your code thoroughly if it usesmultiple ElseIf clauses. Youmust either
make sure they’re listed in the proper order or use upper and lower limits, as in the preceding
sidebar.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 90
90 CHAPTER 3 PROGRAMMING FUNDAMENTALS
The IIf() Function
Not to be confused with the If...Then statement, VB provides the IIf() function. This built-in func-
tion accepts as an argument an expression and two values, evaluates the expression, and returns the
?rst value if the expression is True, or the second value if the expression is False. The syntax of
the IIf() function is the following:
IIf(expression, TruePart, FalsePart)
The TruePart and FalsePart arguments are objects. (They can be integers, strings, or any built-in
or custom object.) The IIf() function is a more compact notation for simple If statements. Let’s
say you want to display one of the strings ‘‘Close’’ or ‘‘Far’’, depending on the value of the distance
variable. Instead of a multiline If statement, you can call the IIf() function as follows:
IIf(distance > 1000, ”Far”, ”Close”)
Another typical example of the IIf() function is in formatting negative values. It’s fairly common in
business applications to display negative amounts in parentheses. Use the IIf() statement to write
a short expression that formats negative and positive amounts differently, like the following one:
IIf(amount < 0, ”(” &
Math.Abs(amount).ToString(”#,###.00”) & ”)”,
amount.ToString(”#,###.00”))
The Abs method of the Math class returns the absolute value of a numeric value, and the string
argument of the ToString method determines that the amount should have two decimal digits.
Select Case
An alternative to the ef?cient but dif?cult-to-read code of the multiple ElseIf structure is the
Select Case structure, which compares the same expression to different values. The advantage of
the Select Case statement over multiple If...Then...ElseIf statements is that it makes the code
easier to read and maintain.
The Select Case structure evaluates a single expression at the top of the structure. The result of
the expression is then compared with several values; if it matches one of them, the corresponding
block of statements is executed. Here’s the syntax of the Select Case statement:
Select Case expression
Case value1
statementblock1
Case value2
statementblock2
.
.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 91
FLOW-CONTROL STATEMENTS 91
.
Case Else
statementblockN
End Select
A practical example based on the Select Case statement is shown in Listing 3.2.
Listing 3.2: Using the Select Case Statement
Dim Message As String
Select Case Now.DayOfWeek
Case DayOfWeek.Monday
message = ”Have a nice week”
Case DayOfWeek.Friday
message = ”Have a nice weekend”
Case Else
message = ”Welcome back!”
End Select
MsgBox(message)
In the listing, the expression that’s evaluated at the beginning of the statement is the
Now.DayOfWeek method. This method returns a member of the DayOfWeek enumeration, and
you can use the names of these members in your code to make it easier to read. The value of
this expression is compared with the values that follow each Case keyword. If they match, the
block of statements up to the next Case keyword is executed, and the program skips to the state-
ment following the End Select statement. The block of the Case Else statement is optional,
and is executed if none of the previous cases matches the expression. The ?rst two Case state-
ments take care of Fridays and Mondays, and the Case Else statement takes care of the
other days.
Some Case statements can be followed by multiple values, which are separated by commas.
Listing 3.3 is a revised version of the previous example.
Listing 3.3: A Select Case StatementwithMultiple Cases per Clause
Select Case Now.DayOfWeek
Case DayOfWeek.Monday
message = ”Have a nice week”
Case DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday
message = ”Welcome back!”
Case DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday
message = ”Have a nice weekend!”
End Select
MsgBox(message)Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 92
92 CHAPTER 3 PROGRAMMING FUNDAMENTALS
Monday, weekends, and weekdays are handled separately by three Case statements. The
second Case statement handles multiple values (all workdays except for Monday and Friday).
Monday is handled by a separate Case statement. This structure doesn’t contain a Case Else
statement because all possible values are examined in the Case statements; the DayOfWeek method
can’t return another value.
The Case statements can get a little more complex. For example, you may want to distinguish
a case where the variable is larger (or smaller) than a value. To implement this logic, use the Is
keyword, as in the following code segment that distinguishes between the ?rst and second half of
the month:
Select Now.Day
Case Is < 15
MsgBox(”It’s the first half of the month”)
Case Is >=15
MsgBox(”It’s the second half of the month”)
End Select
Short-Circuiting Expression Evaluation
A common pitfall of evaluating expressions with VB is to attempt to compare a Nothing value
to something. An object variable that hasn’t been set to a value can’t be used in calculations or
comparisons. Consider the following statements:
Dim B As SolidBrush
B = New SolidBrush(Color.Cyan)
If B.Color = Color.White Then
MsgBox(”Please select another brush color”)
End If
These statements create a SolidBrush object variable, the B variable, and then examine the brush
color and prohibit the user from drawing with a white brush. The second statement initializes the
brush to the cyan color. (Every shape drawn with this brush will appear in cyan.) If you attempt
to use the B variable without initializing it, a runtime exception will be thrown: the infamous
NullReferenceException. In our example, the exception will be thrown when the program gets
to the If statement, because the B variable has no value (it’s Nothing), and the code attempts to
compare it to something. Nothing values can’t be compared to anything. Comment out the second
statement by inserting a single quote in front of it and then execute the code to see what will
happen. Then restore the statement by removing the comment mark.
Let’s ?x it by making sure that B is not Nothing:
If B IsNot Nothing And B.Color = Color.White Then
MsgBox(”Please select another brush color”)
End If
The If statement should compare the Color property of the B object, only if the B object is not
Nothing. But this isn’t the case. The AND operator evaluates all terms in the expression and then
combines their results (True or False values) to determine the value of the expression. If they’re
all True, the result is also True. However, it won’t skip the evaluation of some terms as soon as
it hits a False value. To avoid unnecessary comparisons, use the AndAlso operator. The AndAlsoPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 93
FLOW-CONTROL STATEMENTS 93
operator does what the And operator should have done in the ?rst place: It stops evaluating the
remaining terms or the expression because they won’t affect the result. If one of its operands is
False, the entire expression will evaluate to False. In other words, if B is Nothing, there’s no reason
to compare its color; the entire expression will evaluate to False, regardless of the brush’s color.
Here’s how we use the AndAlso operator:
If B IsNot Nothing AndAlso B.Color = Color.White Then
MsgBox(”Please select another brush color”)
End If
The AndAlso operator is said to short-circuit the evaluation of the entire expression as soon as
it runs into a False value. As soon as one of the parts in an AndAlso operation turns out to be False,
the entire expression is False and there’s no need to evaluate the remaining terms.
There’s an equivalent operator for short-circuiting OR expressions: the OrElse operator. The
OrElse operator can speed the evaluation of logical expressions a little, but it’s not as important
as the AndAlso operator. Another good reason for short-circuiting expression evaluation is to
help performance. If the second term of an And expression takes longer to execute (it has to access
a remote database, for example), you can use the AndAlso operator to make sure that it’s not
executed when not needed.
Loop Statements
Loop statements allow you to execute one or more lines of code repetitively. Many tasks consist of
operations that must be repeated over and over again, and loop statements are an important part
of any programming language. Visual Basic supports the following loop statements:
? For...Next
? Do...Loop
? While...End While
For...Next
Unlike the other two loops, the For...Next loop requires that you know the number of times that
the statements in the loop will be executed. The For...Next loop has the following syntax:
For counter = start To end [Step increment]
statements
Next [counter]
The keywords in the square brackets are optional. The arguments counter, start, end,and
increment are all numeric. The loop is executed as many times as required for the counter to
reach (or exceed) the end value.
In executing a For...Next loop, Visual Basic does the following:
1. Sets counter equal to start.
2. Tests to see whether counter is greater than end. If so, it exits the loop without executing the
statements in the loop’s body, not even once. If increment is negative, Visual Basic tests to
see whether counter is less than end. If it is, it exits the loop.
3. Executes the statements in the block.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 94
94 CHAPTER 3 PROGRAMMING FUNDAMENTALS
4. Increases counter by the amount speci?ed with the increment argument, following the
Step keyword. If the increment argument isn’t speci?ed, counter is increased by 1. If Step
is a negative value, counter is decreased accordingly.
5. Continues with step 3.
The For...Next loop in Listing 3.4 scans all the elements of the numeric array data and calcu-
lates their average.
Listing 3.4: Iterating an Array with a For...Next Loop
Dim i As Integer, total As Double
Fori=0To data.GetUpperBound(0)
total = total + data(i)
Next i
Debug.WriteLine (total / Data.Length)
The single most important thing to keep in mind when working with For...Next loopsisthat
the loop’s ending value is set at the beginning of the loop. Changing the value of the end variable
in the loop’s body won’t have any effect. For example, the following loop will be executed 10
times, not 100 times:
Dim endValue As Integer = 10
Dim i as Integer
Fori=0To endValue
endValue = 100
{ more statements }
Next i
You can, however, adjust the value of the counter from within the loop. The following is an
example of an endless (or in?nite) loop:
Fori=0To10
Debug.WriteLine(i)
i=i-1
Next i
This loop never ends because the loop’s counter, in effect, is never increased. (If you try this,
press Ctrl + Break to interrupt the endless loop.)
Do Not Manipulate the Loop’s Counter
Manipulating the counter of a For...Next loop is strongly discouraged. This practice willmost likely
lead to bugs such as in?nite loops, over?ows, and so on. If the number of repetitions of a loop isn’t
known in advance, use a Do...Loop or a While...End While structure (discussed in the following
section). To jump out of a For...Next loop prematurely, use the Next For statement.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 95
FLOW-CONTROL STATEMENTS 95
The increment argument can be either positive or negative. If start is greater than end,the
value of increment must be negative. If not, the loop’s body won’t be executed, not even once.
VB 2008 allows you to declare the counter in the For statement. The counter variable ceases to
exist when the program bails out of the loop:
For i As Integer = 1 to 10
Debug.WriteLine(i.ToString)
Next
Debug.WriteLine(i.ToString)
The i variable is used as the loop’s counter and it’s not visible outside the loop. The last state-
ment won’t even compile; the editor will underline it with a wiggly line and will generate the error
message Name ‘i’ is not declared.
Do...Loop
The Do...Loop executes a block of statements for as long as a condition is True, or until a condition
becomes True. Visual Basic evaluates an expression (the loop’s condition), and if it’s True, the
statements in the loop’s body are executed. The expression is evaluated either at the beginning
of the loop (before executing any statements) or at the end of the loop (the block statements are
executed at least once). If the expression is False, the program’s execution continues with the
statement following the loop.
There are two variations of the Do...Loop statement; both use the same basic model. A loop
can be executed either while the condition is True or until the condition becomes True. These
two variations use the keywords While and Until to specify for how long the statements will be
executed. To execute a block of statements while a condition is True, use the following syntax:
Do While condition
statement-block
Loop
To execute a block of statements until the condition becomes True, use the following syntax:
Do Until condition
statement-block
Loop
When Visual Basic executes these loops, it ?rst evaluates condition.If condition is False,
a Do...While loop is skipped (the statements aren’t even executed once), but a Do...Until loop
is executed. When the Loop statement is reached, Visual Basic evaluates the expression again; it
repeats the statement block of the Do...While loop if the expression is True or repeats the state-
ments of the Do...Until loop if the expression is False. In short, the Do...While loop is executed
when the condition is True, and the Do...Until loop is executed when the condition is False.
A last variation of the Do...Loop statement allows you to evaluate the condition at the end of the
loop. Here’s the syntax of both loops, with the evaluation of the condition at the end of the loop:
Do
statement-block
Loop While conditionPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 96
96 CHAPTER 3 PROGRAMMING FUNDAMENTALS
Do
statement-block
Loop Until condition
As you can guess, the statements in the loop’s body are executed at least once, because no
testing takes place as the loop is entered.
Here’s a typical example of using a Do...Loop: Suppose that the variable MyText holds some
text (like the Text property of a TextBox control), and you want to count the words in the text.
(We’ll assume that there are no multiple spaces in the text and that the space character separates
successive words.) To locate an instance of a character in a string, use the IndexOf method, which
is discussed in detail in Chapter 13, ‘‘Handling Strings, Characters, and Dates.’’ This method
accepts two arguments: the starting location of the search and the character being searched.
The following loop repeats for as long as there are spaces in the text. Each time the IndexOf
method ?nds another space in the text, it returns the location of the space. When there are no
more spaces in the text, the IndexOf method returns the value –1, which signals the end of the
loop, as shown:
Dim MyText As String =
”The quick brown fox jumped over the lazy dog”
Dim position, words As Integer
position = 0: words = 0
Do While position >=0
position = MyText.IndexOf(” ”, position + 1)
words += 1
Loop
MsgBox(”There are ” & words & ” words in the text”)
The Do...Loop is executed while the IndexOf method function returns a positive number,
which means that there are more spaces (and therefore words) in the text. The variable position
holds the location of each successive space character in the text. The search for the next space starts
at the location of the current space plus 1 (so the program won’t keep ?nding the same space). For
each space found, the program increments the value of the words variable, which holds the total
number of words when the loop ends. By the way, there are simpler methods of breaking a string
into its constituent words, such as the Split method of the String class, which is discussed in
Chapter 13. This is just an example of the Do...While loop.
You might notice a problem with the previous code segment: It assumes that the text contains
at least one word. You should insert an If statement that detects zero-length strings and doesn’t
attempt to count words in them.
You can code the same routine with the Until keyword. In this case, you must continue search-
ing for spaces until position becomes –1. Here’s the same code with a different loop:
Dim position As Integer = 0
Dim words As Integer = 0
Do Until position = -1
position = MyText.IndexOf(” ”, position + 1)
words = words + 1
Loop
MsgBox(”There are ” & words & ” words in the text”)Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 97
FLOW-CONTROL STATEMENTS 97
While...End While
The While...End While loop executes a block of statements as long as a condition is True. The loop
has the following syntax:
While condition
statement-block
End While
If condition is True, all statements in the bock are executed. When the End While statement
is reached, control is returned to the While statement, which evaluates condition again. If con-
dition is still True, the process is repeated. If condition is False, the program resumes with the
statement following End While.
The loop in Listing 3.5 prompts the user for numeric data. The user can type a negative value
to indicate he’s done entering values and terminate the loop. As long as the user enters positive
numeric values, the program keeps adding them to the total variable.
Listing 3.5: Reading an Unknown Number of Values
Dim number, total As Double
number = 0
While number => 0
total = total + number
number = InputBox(”Please enter another value”)
End While
I’ve assigned the value 0 to the number variable before the loop starts because this value isn’t
negative and doesn’t affect the total.
Sometimes, the condition that determines when the loop will terminate can’t be evaluated at
the top of the loop. In these cases, we declare a Boolean value and set it to True or False from
within the loop’s body. Here’s the outline of such a loop:
Dim repeatLoop As Boolean
repeatLoop = True
While repeatLoop
{ statements }
If condition Then
repeatLoop = True
Else
repeattLoop = False
End If
End While
You may also see an odd loop statement like the following one:
While True
{ statements }
End WhilePetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 98
98 CHAPTER 3 PROGRAMMING FUNDAMENTALS
It’s also common to express the True condition as follows:
While1=1
This seemingly endless loop must be terminated from within its own body with an Exit While
statement, which is called when a condition becomes True or False. The following loop terminates
when a condition is met in the loop’s body:
While True
{ statements }
If condition Then Exit While
{ more statements }
End While
Nested Control Structures
You can place, or nest, control structures inside other control structures (such as an If...Then
block within a For...Next loop). Control structures in Visual Basic can be nested in as many levels
as you want. The editor automatically indents the bodies of nested decision and loop structures to
make the program easier to read.
When you nest control structures, you must make sure that they open and close within the
same structure. In other words, you can’t start a For...Next loop in an If statement and close
the loop after the corresponding End If. The following code segment demonstrates how to nest
several ?ow-control statements. (The curly brackets denote that regular statements should appear
in their place and will not compile, of course.)
Fora=1To100
{ statements }
Ifa=99 Then
{ statements }
End If
While b < a
{ statements }
If total <= 0 Then
{ statements }
End If
End While
Forc=1toa
{ statements }
Next c
Next a
I’m showing the names of the counter variables after the Next statements to make the code
more readable. To ?nd the matching closing statement (Next, End If,or End While), move down
from the opening statement until you hit a line that starts at the same column. This is the matching
closing statement. Notice that you don’t have to align the nested structures yourself; the editor
reformats the code automatically as you edit. It also inserts the matching closing statement— the
End If statement is inserted automatically as soon as you enter an If statement, for example.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 99
FLOW-CONTROL STATEMENTS 99
Listing 3.6 shows the structure of a nested For...Next loop that scans all the elements of a
two-dimensional array.
Listing 3.6: Iterating through a Two-Dimensional Array
Dim Array2D(6, 4) As Integer
Dim iRow, iCol As Integer
For iRow = 0 To Array2D.GetUpperBound(0)
For iCol = 0 To Array2D.GetUpperBound(1)
Array2D(iRow, iCol) = iRow * 100 + iCol
Debug.Write(iRow & ”, ” & iCol & ”=”&
Array2D(iRow, iCol) & ” ”)
Next iCol
Debug.WriteLine()
Next iRow
The outer loop (with the iRow counter) scans each row of the array. At each iteration, the inner
loop scans all the elements in the row speci?ed by the counter of the outer loop (iRow). After
the inner loop completes, the counter of the outer loop is increased by one, and the inner loop is
executed again — this time to scan the elements of the next row. The loop’s body consists of two
statements that assign a value to the current array element and then print it in the Output window.
The current element at each iteration is Array2D(iRow, iCol).
You can also nest multiple If statements. The code in Listing 3.7 tests a user-supplied value to
determine whether it’s positive; if so, it determines whether the value exceeds a certain limit.
Listing 3.7: Simple Nested If Statements
Dim Income As Decimal
Income = Convert.ToDecimal(InputBox(”Enter your income”))
If Income > 0 Then
If Income > 12000 Then
MsgBox ”You will pay taxes this year”
Else
MsgBox ”You won’t pay any taxes this year”
End If
Else
MsgBox ”Bummer”
End If
The Income variable is ?rst comparedwith zero. If it’s negative, the Else clause of the If...Then
statement is executed. If it’s positive, it’s compared with the value 12,000, and depending on
the outcome, a different message is displayed. The code segment shown here doesn’t perform
any extensive validations and assumes that the user won’t enter a string when prompted for
her income.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 100
100 CHAPTER 3 PROGRAMMING FUNDAMENTALS
The Exit Statement
The Exit statement allows you to exit prematurely from a block of statements in a control struc-
ture, from a loop, or even from a procedure. Suppose that you have a For...Next loop that
calculates the square root of a series of numbers. Because the square root of negative numbers
can’t be calculated (the Math.Sqrt method will generate a runtime error), you might want to halt
the operation if the array contains an invalid value. To exit the loop prematurely, use the Exit For
statement as follows:
Fori=0To UBound(nArray)
If nArray(i) < 0 Then
MsgBox(”Can’t complete calculations” & vbCrLf &
”Item ” & i.ToString & ” is negative! ”
Exit For
End If
nArray(i) = Math.Sqrt(nArray(i))
Next
If a negative element is found in this loop, the program exits the loop and continues with the
statement following the Next statement.
There are similar Exit statements for the Do loop (Exit Do), the While loop (Exit While), the
Select statement (Exit Select), and for functions and subroutines (Exit Function and Exit
Sub). If the previous loop was part of a function, you might want to display an error and exit not
only the loop, but also the function itself by using the Exit Function statement.
Writing andUsing Procedures
The idea of breaking a large application into smaller, more manageable sections is not new to
computing. Few tasks, programming or otherwise, can bemanaged as a whole. The event handlers
are just one example of breaking a large application into smaller tasks.
For example, when you write code for a control’s Click event, you concentrate on the event
at hand — namely, how the program should react to the Click event. What happens when the
control is double-clicked or when another control is clicked is something you will worry about
later — in another control’s event handler. This divide-and-conquer approach isn’t unique to
programming events. It permeates the Visual Basic language, and even the longest applications are
written by breaking them into small, well-de?ned, easily managed tasks. Each task is performed
by a separate procedure that is written and tested separately fromthe others. Asmentioned earlier,
the two types of procedures supported by Visual Basic are subroutines and functions.
Subroutines usually perform actions and they don’t return any result. Functions, on the other
hand,performsomecalculationsandreturnavalue.Thisistheonlydifferencebetweensubrou-
tines and functions. Both subroutines and functions can accept arguments, which are values you
pass to the procedure when you call it. Usually, the arguments are the values on which the proce-
dure’s code acts. Arguments and the related keywords are discussed in detail in the ‘‘Arguments’’
section later in this chapter.
Subroutines
A subroutine is a block of statements that carries out a well-de?ned task. The block of state-
ments is placed within a set of Sub...End Sub statements and can be invoked by name.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 101
WRITING AND USING PROCEDURES 101
The following subroutine displays the current date in a message box and can be called by its name,
ShowDate():
Sub ShowDate()
MsgBox(Now().ToShortDateString)
End Sub
Normally, the task performed by a subroutine is more complicated than this; but even this
simple subroutine is a block of code isolated from the rest of the application. The statements in a
subroutine are executed, and when the End Sub statement is reached, control returns to the calling
program. It’s possible to exit a subroutine prematurely by using the Exit Sub statement.
All variables declared within a subroutine are local to that subroutine. When the subroutine
exits, all variables declared in it cease to exist.
Most procedures also accept and act upon arguments. The ShowDate() subroutine displays the
current date in a message box. If you want to display any other date, you have to implement it
differently and add an argument to the subroutine:
Sub ShowDate(ByVal birthDate As Date)
MsgBox(birthDate.ToShortDateString)
End Sub
birthDate is a variable that holds the date to be displayed; its type is Date. The ByVal keyword
means that the subroutine sees a copy of the variable, not the variable itself. What this means
practically is that the subroutine can’t change the value of the variable passed by the calling appli-
cation. To display the current date in a message box, you must call the ShowDate() subroutine as
follows from within your program:
ShowDate()
To display any other date with the second implementation of the subroutine, use a statement
like the following:
Dim myBirthDate = #2/9/1960#
ShowDate(myBirthDate)
Or, you can pass the value to be displayed directly without the use of an intermediate variable:
ShowDate(#2/9/1960#)
If you later decide to change the format of the date, there’s only one place in your code you
must edit: the statement that displays the date from within the ShowDate() subroutine.
Functions
A function is similar to a subroutine, but a function returns a result. Because they return values,
functions — like variables — have types. The value you pass back to the calling program from
a function is called the return value, and its type must match the type of the function. FunctionsPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 102
102 CHAPTER 3 PROGRAMMING FUNDAMENTALS
accept arguments, just like subroutines. The statements that make up a function are placed in a set
of Function...End Function statements, as shown here:
Function NextDay() As Date
Dim theNextDay As Date
theNextDay = Now.AddDays(1)
Return theNextDay
End Function
The Function keyword is followed by the function name and the As keyword that speci?es its
type, similar to a variable declaration. AddDays is a method of the Date type, and it adds a number
of days to a Date value. The NextDay() function returns tomorrow’s date by adding one day to the
current date. NextDay() is a custom function, which calls the built-in AddDays method to complete
its calculations.
The result of a function is returned to the calling program with the Return statement, which
is followed by the value you want to return from your function. This value, which is usually a
variable, must be of the same type as the function. In our example, the Return statement happens
to be the last statement in the function, but it could appear anywhere; it could even appear several
times in the function’s code. The ?rst time a Return statement is executed, the function terminates,
and control is returned to the calling program.
You can also return a value to the calling routine by assigning the result to the name of the
function. The following is an alternate method of coding the NextDay() function:
Function NextDay() As Date
NextDay = Now.AddDays(1)
End Function
Notice that this time I’ve assigned the result of the calculation to the function’s name directly
and didn’t use a variable. This assignment, however, doesn’t terminate the function like the
Return statement. It sets up the function’s return value, but the function will terminate when
the End Function statement is reached, or when an Exit Function statement is encountered.
Similar to variables, a custom function has a name that must be unique in its scope (which is
also true for subroutines, of course). If you declare a function in a form, the function name must be
unique in the form. If you declare a function as Public or Friend, its name must be unique in the
project. Functions have the same scope rules as variables and can be pre?xed by many of the same
keywords. In effect, you can modify the default scope of a function with the keywords Public,
Private, Protected, Friend,and Protected Friend. In addition, functions have types, just like
variables, and they’re declared with the As keyword.
Suppose that the function CountWords() counts the number of words, and the function
CountChars() counts the number of characters in a string. The average length of a word could
be calculated as follows:
Dim longString As String, avgLen As Double
longString = TextBox1.Text
avgLen = CountChars(longString) / CountWords(longString)
The ?rst executable statement gets the text of a TextBox control and assigns it to a variable,
which is then used as an argument to the two functions.When the third statement executes, VisualPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 103
ARGUMENTS 103
Basic ?rst calls the functions CountChars() and CountWords() with the speci?ed arguments, and
then divides the results they return.
You can call functions in the same way that you call subroutines, but the result won’t be stored
anywhere. For example, the function Convert() might convert the text in a text box to uppercase
and return the number of characters it converts. Normally, you’d call this function as follows:
nChars = Convert()
If you don’t care about the return value — you only want to update the text on a TextBox
control — you would call the Convert() function with the following statement:
Convert()
Arguments
Subroutines and functions aren’t entirely isolated from the rest of the application. Most proce-
dures accept arguments from the calling program. Recall that an argument is a value you pass to
the procedure and on which the procedure usually acts. This is how subroutines and functions
communicate with the rest of the application.
Subroutines and functions may accept any number of arguments, and you must supply a value
for each argument of the procedure when you call it. Some of the arguments may be optional,
which means you can omit them; you will see shortly how to handle optional arguments.
The custom function Min(), for instance, accepts two numbers and returns the smaller one:
Function Min(ByVal a As Single, ByVal b As Single) As Single
Min = IIf(a < b, a, b)
End Function
IIf() is a built-in function that evaluates the ?rst argument, which is a logical expression. If
the expression is True, the IIf() function returns the second argument. If the expression is False,
the function returns the third argument.
To call the Min() custom function, use a few statements like the following:
Dim val1 As Single = 33.001
Dim val2 As Single = 33.0011
Dim smallerVal as Single
smallerVal = Min(val1, val2)
Debug.Write(”The smaller value is ” & smallerVal)
If you execute these statements (place them in a button’s Click event handler), you will see the
following in the Immediate window:
The smaller value is 33.001
If you attempt to call the same function with two Double values, with a statement like the
following, you will see the value 3.33 in the Immediate window:
Debug.WriteLine(Min(3.33000000111, 3.33000000222))Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 104
104 CHAPTER 3 PROGRAMMING FUNDAMENTALS
The compiler converted the two values from Double to Single data type and returned one of
them. Which one is it? It doesn’t make a difference because when converted to Single, both values
are the same.
Interesting things will happen if you attempt to use the Min() function with the Strict option
turned on. Insert the statement Option Strict On at the very beginning of the ?le, or set Option
Strict to On in the Compile tab of the project’s Properties pages. The editor will underline the
statement that implements the Min() function: the IIf() function. The IIf() function accepts
two Object variables as arguments, and returns one of them as its result. The Strict option prevents
the compiler from converting an Object to a numeric variable. To use the IIf() function with the
Strict option, you must change its implementation as follows:
Function Min(ByVal a As Object, ByVal b As Object) As Object
Min = IIf(Val(a) < Val(b), a, b)
End Function
It’s possible to implement a Min() function that can compare arguments of all types (integers,
strings, dates, and so on). We’ll return to this sample function later in this chapter, in the section
‘‘Overloading Functions.’’
Argument-Passing Mechanisms
One of the most important topics in implementing your own procedures is the mechanism used
to pass arguments. The examples so far have used the default mechanism: passing arguments by
value. The other mechanism is passing them by reference. Although most programmers use the
default mechanism, it’s important to know the difference between the two mechanisms and when
to use each.
By Value versus by Reference
When you pass an argument by value, the procedure sees only a copy of the argument. Even if
the procedure changes it, the changes aren’t permanent; in other words, the value of the original
variable passed to the procedure isn’t affected. The bene?t of passing arguments by value is that
the argument values are isolated from the procedure, and only the code segment in which they
are declared can change their values. This is the default argument-passing mechanism in Visual
Basic 2008.
In VB 6, the default argument-passing mechanism was by reference, and this is something you
should be aware of, especially if you’re migrating VB 6 code to VB 2008.
To specify the arguments that will be passed by value, use the ByVal keyword in front of the
argument’s name. If you omit the ByVal keyword, the editor will insert it automatically because
it’s the default option. To declare that the Degrees() function’s argument is passed by value, use
the ByVal keyword in the argument’s declaration as follows:
Function Degrees(ByVal Celsius as Single) As Single
Return((9 / 5) * Celsius + 32)
End FunctionPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 105
ARGUMENTS 105
To see what the ByVal keyword does, add a line that changes the value of the argument
in the function:
Function Degrees(ByVal Celsius as Single) As Single
Return((9 / 5) * Celsius + 32)
Celsius = 0
End Function
Now call the function as follows:
CTemp = InputBox(”Enter temperature in degrees Celsius”)
MsgBox(CTemp.ToString & ” degrees Celsius are ” &
Degrees((CTemp)) & ” degrees Fahrenheit”)
If you enter the value 32, the following message is displayed:
32 degrees Celsius are 89.6 degrees Fahrenheit
Replace the ByVal keyword with the ByRef keyword in the function’s de?nition and call the
function as follows:
Celsius = 32.0
FTemp = Degrees(Celsius)
MsgBox(Celsius.ToString & ” degrees Celsius are ” & FTemp &
” degrees Fahrenheit”)
This time the program displays the following message:
0 degrees Celsius are 89.6 degrees Fahrenheit
When the Celsius argument was passed to the Degrees() function, its value was 32. But
the function changed its value, and upon return it was 0. Because the argument was passed by
reference, any changes made by the procedure affected the variable permanently. As a result,
when the calling program attempted to use it, the variable had a different value than expected.
Returning Multiple Values
If you want to write a function that returns more than a single result, you will most likely pass
additional arguments by reference and set their values from within the function’s code. The
CalculateStatistics() function, shown a little later in this section, calculates the basic statistics
of a data set. The values of the data set are stored in an array, which is passed to the function
by reference. The CalculateStatistics() function must return two values: the average and
standard deviation of the data set. Here’s the declaration of the CalculateStatistics() function:
Function CalculateStatistics(ByRef Data() As Double,
ByRef Avg As Double, ByRef StDev As Double) As IntegerPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 106
106 CHAPTER 3 PROGRAMMING FUNDAMENTALS
The function returns an integer, which is the number of values in the data set. The two impor-
tant values calculated by the function are returned in the Avg and StDev arguments:
Function CalculateStatistics(ByRef Data() As Double,
ByRef Avg As Double, ByRef StDev As Double) As Integer
Dim i As Integer, sum As Double, sumSqr As Double, points As Integer
points = Data.Length
Fori=0To points - 1
sum = sum + Data(i)
sumSqr = sumSqr + Data(i) ˆ 2
Next
Avg = sum / points
StDev = System.Math.Sqrt(sumSqr / points - Avg ˆ 2)
Return(points)
End Function
To call the CalculateStatistics() function fromwithin your code, set up an array of Doubles
and declare two variables that will hold the average and standard deviation of the data set:
Dim Values(99) As Double
‘ Statements to populate the data set
Dim average, deviation As Double
Dim points As Integer
points = Stats(Values, average, deviation)
Debug.WriteLine points & ” values processed.”
Debug.WriteLine ”The average is ” & average & ” and”
Debug.WriteLine ”the standard deviation is ” & deviation
Using ByRef arguments is the simplest method for a function to return multiple values. How-
ever, the de?nition of your functionsmight become cluttered, especially if you want to returnmore
than a few values. Another problem with this technique is that it’s not clear whether an argument
must be set before calling the function. As you will see shortly, it is possible for a function to return
an array or a custom structure with ?elds for any number of values.
Passing Objects as Arguments
When you pass objects as arguments, they’re passed by reference, even if you have speci?ed the
ByVal keyword. The procedure can access and modify the members of the object passed as an
argument, and the new value will be visible in the procedure that made the call.
The following code segment demonstrates this. The object is an ArrayList, which is an enhanced
form of an array. The ArrayList is discussed in detail later in the book, but to follow this example
all you need to know is that the Add method adds new items to the ArrayList, and you can access
individual items with an index value, similar to an array’s elements. In the Click event handler
of a Button control, create a new instance of the ArrayList object and call the PopulateList()
subroutine to populate the list. Even if the ArrayList object is passed to the subroutine by value,
the subroutine has access to its items:
Private Sub Button1 Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
Dim aList As New ArrayList()
PopulateList(aList)Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 107
ARGUMENTS 107
Debug.WriteLine(aList(0).ToString)
Debug.WriteLine(aList(1).ToString)
Debug.WriteLine(aList(2).ToString)
End Sub
Sub PopulateList(ByVal list As ArrayList)
list.Add(”1”)
list.Add(”2”)
list.Add(”3”)
End Sub
The same is true for arrays and all other collections. Even if you specify the ByVal keyword,
they’re passed by reference. A more elegant method of modifying the members of a structure from
within a procedure is to implement the procedure as a function returning a structure, as explained
in the section ‘‘Functions Returning Structures,’’ later in this chapter.
Built-in Functions
VB 2008 provides many functions that implement common or complicated tasks, and you can look
them up in the documentation. (You’ll ?nd them in the Visual Studio Visual Basic  Reference
 Functions branch of the contents tree in the Visual Studio documentation.) There are functions
for the common math operations, functions to perform calculations with dates (these are truly
complicated operations), ?nancial functions, andmany more.When you use the built-in functions,
you don’t have to know how they work internally — just how to call them and how to retrieve the
return value.
The Pmt() function, for example, calculates the monthly payments on a loan. All you have to
know is the arguments you must pass to the function and how to retrieve the result. The syntax
of the Pmt() function is the following, where MPay is the monthly payment, Rate is the monthly
interest rate, and NPer is the number of payments (the duration of the loan in months). PV is the
loan’s present value (the amount you took from the bank):
MPay = Pmt(Rate, NPer, PV, FV, Due)
Due is an optional argument that speci?es when the payments are due (the beginning or the end
of the month), and FV is another optional argument that speci?es the future value of an amount.
This isn’t needed in the case of a loan, but it can help you calculate how much money you should
deposit each month to accumulate a target amount over a given time. (The amount returned by
the Pmt() function is negative because it’s a negative cash ?ow— it’s money you owe — so pay
attention to the sign of your values.)
To calculate the monthly payment for a $20,000 loan paid off over a period of six years at a
?xed interest rate of 7.25%, you call the Pmt() function, as shown in Listing 3.8.
Listing 3.8: Using the Pmt() Built-in Function
Dim mPay, totalPay As Double
Dim Duration As Integer = 6 * 12
Dim Rate As Single = (7.25 / 100) / 12
Dim Amount As Single = 20000
mPay = -Pmt(Rate, Duration, Amount)Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 108
108 CHAPTER 3 PROGRAMMING FUNDAMENTALS
totalPay = mPay * Duration
MsgBox(”Your monthly payment will be ” & mPay.ToString(”C”) &
vbCrLf & ”You will pay back a total of ” &
totalPay.ToString(”C”))
Notice that the interest (7.25%) is divided by 12 because the function requires the monthly
interest. The value returned by the function is the monthly payment for the loan speci?ed with
the Duration, Amount,and Rate variables. If you place the preceding lines in the Click event
handler of a Button, run the project, and then click the button, the following message will appear
in a message box:
Your monthly payment will be $343.39
You will pay back a total of $24,723.80
Let’s say you want to accumulate $40,000 over the next 15 years by making monthly deposits
of equal amounts. To calculate the monthly deposit amount, you must call the Pmt() function,
passing 0 as the present value and the target amount as the future value. Replace the statements
in the button’s Click event handler with the following and run the project:
Dim mPay As Double
Dim Duration As Integer = 15 * 12
Dim Rate As Single = (4.0 / 100.0) / 12
Dim Amount As Single = -40000.0
mPay = Pmt(Rate, Duration, 0, Amount)
MsgBox(”A monthly deposit of ” & mPay.ToString(”C”) & vbCrLf &
”every month will yield $40,000 in 15 years”)
It turns out that if you want to accumulate $40,000 over the next 15 years to send your kid to
college, assuming a constant interest rate of 4%, you must deposit $162.54 every month. You’ll put
out almost $30,000, and the rest will be the interest you earn.
Pmt() is one of the simpler ?nancial functions provided by the Framework, but most of us
would ?nd it really dif?cult to write the code for this function. Because ?nancial calculations are
quite common in business programming, many of the functions you might need already exist, and
all you need to know is how to call them. If you’re developing ?nancial applications, you should
look up the ?nancial functions in the documentation.
Let’s look at another useful built-in function, the MonthName() function, which accepts as an
argument amonth number and returns the name of themonth. This function is not as trivial as you
might think because it returns the month name or its abbreviation in the language of the current
culture. The MonthName() function accepts as arguments the month number and a True/False
value that determines whether it will return the abbreviation or the full name of the month. The
following statements display the name of the current month (both the abbreviation and the full
name). Every time you execute these statements, you will see the current month’s name in the
current language:
Dim mName As String
mName = MonthName(Now.Month, True)
MsgBox(mName) ‘ prints ”Jan”
mName = MonthName(Now.Month, False)
MsgBox(mName) ‘ prints ”January”Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 109
ARGUMENTS 109
A similar function, the WeekDayName() function, returns the name of the week for a speci?c
weekday. This function accepts an additional argument that determines the ?rst day of the week.
(See the documentation for more information on the syntax of the WeekDayName() function.)
The primary role of functions is to extend the functionality of the language.Many functions that
perform rather common practical operations have been included in the language, but they aren’t
nearly enough for the needs of all developers or all types of applications. Besides the built-in func-
tions, you can write custom functions to simplify the development of your custom applications, as
explained in the following section.
Custom Functions
Most of the code we write is in the form of custom functions or subroutines that are called from
several places in the application. Subroutines are just like functions, except that they don’t return a
value, so we’ll focus on the implementation of custom functions.With the exception of a function’s
return value, everything else presented in this and the following section applies to subroutines
as well.
Let’s look at an example of a fairly simple (but not trivial) function that does something really
useful. Books are identi?ed by a unique international standard book number (ISBN), and every
application that manages books needs a function to verify the ISBN, which is made up of 12 dig-
its followed by a check digit. To calculate the check digit, you multiply each of the 12 digits by a
constant; the ?rst digit is multiplied by 1, the second digit is multiplied by 3, the third digit by 1
again, and so on. The sum of these multiplications is then divided by 10, and we take the remain-
der. The check digit is this remainder subtracted from 10. To calculate the check digit for the ISBN
978078212283, compute the sum of the following products:
9*1+7*3+8*1+0*3+7*1+8*3+
2*1+1*3+2*1+2*3+8*1+3*3=99
The sum is 99; when you divide it by 10, the remainder is 9. The check digit is 10 – 9, or 1, and
the book’s complete ISBN is 9780782122831. The ISBNCheckDigit() function, shown in Listing
3.9, accepts the 12 digits of the ISBN as an argument and returns the appropriate check digit.
Listing 3.9: The ISBNCheckDigit() CustomFunction
Function ISBNCheckDigit(ByVal ISBN As String) As String
Dim i As Integer, chksum As Integer = 0
Dim chkDigit As Integer
Dim factor As Integer = 3
Fori=0To11
factor = 4 - factor
chksum += factor * Convert.ToInt16(ISBN.Substring(i, 1))
Next
Return (((10 - (chksum Mod 10)) Mod 10)).ToString
End Function
The ISBNCheckDigit() function returns a string value because ISBNs are handled as strings,
not numbers. (Leading zeros are important in an ISBN but are totally meaningless, and omitted,
in a numeric value.) The Substring method of a String object extracts a number of characters
from the string to which it’s applied. The ?rst argument is the starting location in the string, andPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 110
110 CHAPTER 3 PROGRAMMING FUNDAMENTALS
the second is the number of characters to be extracted. The expression ISBN.Substring(i, 1)
extracts one character at a time from the ISBN string variable. During the ?rst iteration of the loop,
it extracts the ?rst character; during the second iteration, it extracts the second character, and
so on.
The extracted character is a numeric digit, which is multiplied by the factor variable value
and the result is added to the chkSum variable. This variable is the checksum of the ISBN. After it
has been calculated, we divide it by 10 and take its remainder (the ?rst Mod operator returns the
remainder of this division), which we subtract from 10. The second Mod operator maps the value
10 to 0. This is the ISBN’s check digit and the function’s return value.
You can use this function in an application that maintains a book database to make sure that
all books are entered with a valid ISBN. You can also use it with a web application that allows
viewers to request books by their ISBN. The same code will work with two different applications,
even when passed to other developers. Developers using your function don’t have to know how
the check digit is calculated, just how to call the function and retrieve its result.
To test the ISBNCheckDigit() function, start a new project, place a button on the form, and
enter the following statements in its Click event handler (or open the ISBN project in the folder
with this chapter’s sample projects):
Private Sub Button1 Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click
Console.WriteLine(”The check Digit is ” &
ISBNCheckDigit(”978078212283”))
End Sub
After inserting the code of the ISBNCheckDigit() function and the code that calls the func-
tion, your code editor should look like Figure 3.1. You can place a TextBox control on the form
and pass the Text property of the control to the ISBNCheckDigit() function to calculate the
check digit.
A similar algorithm is used for calculating the check digit of credit cards: the Luhns algo-
rithm. You can look it up on the Internet and write a custom function for validating credit
card numbers.
Figure 3.1
Calling the ISBNCheck-
Digit() functionPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 111
ARGUMENTS 111
Passing Arguments and Returning Values
So far you’ve learned how to write and call procedures with a few simple arguments and how to
retrieve the function’s return value and use it in your code. This section covers a few advanced
topics on argument-passing techniques and how to write functions that return multiple values, or
arrays of values and custom data types.
Passing an Unknown Number of Arguments
Generally, all the arguments that a procedure expects are listed in the procedure’s de?nition,
and the program that calls the procedure must supply values for all arguments. On occasion,
however, you might not know how many arguments will be passed to the procedure. Procedures
that calculate averages or, in general, process multiple values can accept from a few to several
arguments whose count is not known at design time. VB 2008 supports the ParamArray keyword,
which allows you to pass a variable number of arguments to a procedure.
Let’s look at an example. Suppose that you want to populate a ListBox control with elements.
To add an item to the ListBox control, you call the Add method of its Items collection as follows:
ListBox1.Items.Add(”new item”)
This statement adds the string new item to the ListBox1 control. If you frequently add multiple
items to a ListBox control from within your code, you can write a subroutine that performs this
task. The following subroutine adds a variable number of arguments to the ListBox1 control:
Sub AddNamesToList(ByVal ParamArray NamesArray() As Object)
Dim x As Object
For Each x In NamesArray
ListBox1.Items.Add(x)
Next x
End Sub
This subroutine’s argument is an array pre?xed with the keyword ParamArray, which holds
all the parameters passed to the subroutine. If the parameter array holds items of the same type,
you can declare the array to be of the speci?c type (string, integer, and so on). To add items to the
list, call the AddNamesToList() subroutine as follows:
AddNamesToList(”Robert”, ”Manny”, ”Renee”, ”Charles”, ”Madonna”)
If you want to know the number of arguments actually passed to the procedure, use the Length
property of the parameter array. The number of arguments passed to the AddNamesToList()
subroutine is given by the following expression:
NamesArray.Length
The following loop goes through all the elements of the NamesArray and adds them to the list:
Dim i As Integer
Fori=0to NamesArray.GetUpperBound(0)
ListBox1.Items.Add(NamesArray(i))
Next iPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 112
112 CHAPTER 3 PROGRAMMING FUNDAMENTALS
VB arrays are zero-based (the index of the ?rst item is 0), and the GetUpperBound method
returns the index of the last item in the array.
A procedure that accepts multiple arguments relies on the order of the arguments. To omit
some of the arguments, you must use the corresponding comma. Let’s say you want to call such
a procedure and specify the ?rst, third, and fourth arguments. The procedure must be called as
follows:
ProcName(arg1, , arg3, arg4)
The arguments to similar procedures are usually of equal stature, and their order doesn’t make
any difference. A function that calculates the mean or other basic statistics of a set of numbers,
or a subroutine that populates a ListBox or ComboBox control, are prime candidates for imple-
menting this technique. If the procedure accepts a variable number of arguments that aren’t equal
in stature, you should consider the technique described in the following section. If the function
accepts a parameter array, this must the last argument in the list, and none of the other parameters
can be optional.
Named Arguments
You learned how to write procedures with optional arguments and how to pass a variable number
of arguments to the procedure. The main limitation of the argument-passing mechanism, though,
is the order of the arguments. By default, Visual Basic matches the values passed to a procedure to
the declared arguments by their order (which is why the arguments you’ve seen so far are called
positional arguments).
This limitation is lifted by Visual Basic’s capability to specify named arguments.Withnamed
arguments, you can supply arguments in any order because they are recognized by name and not
by their order in the list of the procedure’s arguments. Suppose you’ve written a function that
expects three arguments: a name, an address, and an email address:
Function Contact(Name As String, Address As String, EMail As String)
When calling this function, you must supply three strings that correspond to the arguments
Name, Address,and EMail, in that order. However, there’s a safer way to call this function: Supply
the arguments in any order by their names. Instead of calling the Contact() function as follows:
Contact(”Peter Evans”, ”2020 Palm Ave., Santa Barbara, CA 90000”,
”PeterEvans@example.com”)
you can call it this way:
Contact(Address:=”2020 Palm Ave., Santa Barbara, CA 90000”,
EMail:=”PeterEvans@example.com”, Name:=”Peter Evans”)
The := operator assigns values to the named arguments. Because the arguments are passed by
name, you can supply them in any order.
To test this technique, enter the following function declaration in a form’s code:
Function Contact(ByVal Name As String, ByVal Address As String,
ByVal EMail As String) As String
Debug.WriteLine(Name)Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 113
ARGUMENTS 113
Debug.WriteLine(Address)
Debug.WriteLine(EMail)
Return (”OK”)
End Function
Then call the Contact() function from within a button’s Click event with the following
statement:
Debug.WriteLine(
Contact(Address:=”2020 Palm Ave., Santa Barbara, CA 90000”,
Name:=”Peter Evans”, EMail:=”PeterEvans@example.com”))
You’ll see the following in the Immediate window:
Peter Evans
2020 Palm Ave., Santa Barbara, CA 90000
PeterEvans@example.com
OK
The function knows which value corresponds to which argument and can process them the
same way that it processes positional arguments. Notice that the function’s de?nition is the same,
whether you call it with positional or named arguments. The difference is in how you call the
function and not how you declare it.
Named arguments make code safer and easier to read, but because they require a lot of typing,
most programmers don’t use them. Besides, when IntelliSense is on, you can see the de?nition of
the function as you enter the arguments, and this minimizes the chances of swapping two values
by mistake.
More Types of Function Return Values
Functions are not limited to returning simple data types such as integers or strings. They might
return custom data types and even arrays. The capability of functions to return all types of data
makes them very ?exible and can simplify coding, so we’ll explore it in detail in the following
sections. Using complex data types, such as structures and arrays, allows you to write functions
that return multiple values.
Functions Returning Structures
Suppose you need a function that returns a customer’s savings and checking account balances.
So far, you’ve learned that you can return two or more values from a function by supplying
arguments with the ByRef keyword. A more elegant method is to create a custom data type
(a structure) and write a function that returns a variable of this type.
Here’s a simple example of a function that returns a custom data type. This example outlines
the steps you must repeat every time you want to create functions that return custom data types:
1. Create a new project and insert the declarations of a custom data type in the declarations
section of the form:
Structure CustBalance
Dim SavingsBalance As Decimal
Dim CheckingBalance As Decimal
End StructurePetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 114
114 CHAPTER 3 PROGRAMMING FUNDAMENTALS
2. Implement the function that returns a value of the custom type. In the function’s body, you
must declare a variable of the type returned by the function and assign the proper values
to its ?elds. The following function assigns random values to the ?elds CheckingBalance
and SavingsBalance. Then assign the variable to the function’s name, as shown next:
Function GetCustBalance(ID As Long) As CustBalance
Dim tBalance As CustBalance
tBalance.CheckingBalance = CDec(1000 + 4000 * rnd())
tBalance.SavingsBalance = CDec(1000 + 15000 * rnd())
Return(tBalance)
End Function
3. Place a button on the form from which you want to call the function. Declare a variable
of the same type and assign to it the function’s return value. The example that follows prints
the savings and checking balances in the Output window:
Private Sub Button1 Click(...) Handles Button1.Click
Dim balance As CustBalance
balance = GetCustBalance(1)
Debug.WriteLine(balance.CheckingBalance)
Debug.WriteLine(balance.SavingsBalance)
End Sub
The code shown in this section belongs to the Structures sample project. Create this project from
scratch, perhaps by using your own custom data type, to explore its structure and experiment with
functions that return custom data types. In Chapter 10, ‘‘Building Custom Classes,’’ you’ll learn
how to build your own classes and you’ll see how to write functions that return custom objects.
VB 2008 at Work: The Types Project
The Types project, which you’ll ?nd in this chapter’s folder, demonstrates a function that returns a
custom data type. The Types project consists of a form that displays record ?elds (see Figure 3.2).
Figure 3.2
The Types project
demonstrates functions
that return custom data
types.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 115
ARGUMENTS 115
Every time you click the Next button, the ?elds of the next record are displayed in the correspond-
ing TextBox controls on the form. When all records are exhausted, the program wraps back to the
?rst record.
The project consists of a single form and uses a custom data type, implemented with the follow-
ing structure. The structure’s declaration must appear in the form’s code, outside any procedure,
along with a couple of variable declarations:
Structure Customer
Dim Company As String
Dim Manager As String
Dim Address As String
Dim City As String
Dim Country As String
Dim CustomerSince As Date
Dim Balance As Decimal
End Structure
Private Customers(9) As Customer
Private cust As Customer
Private currentIndex as Integer
The array Customers holds the data for 10 customers, and the cust variable is used as a tem-
porary variable for storing the current customer’s data. The currentIndex variable is the index
of the current element of the array. The array is ?lled with Customer data, and the currentIndex
variable is initialized to zero.
The Click event handler of the Next button calls the GetCustomer() function with an index
value (which is the order of the current customer) to retrieve the data of the next customer, and
displays the customer’s ?elds on the Label controls on the form with the ShowCustomer() subrou-
tine. Then it increases the value of the currentIndex variable to point to the current customer’s
index. You can open the Types project in Visual Studio and examine its code, which contains quite
a few comments explaining its operation.
Functions Returning Arrays
In addition to returning custom data types, VB 2008 functions can also return arrays. This is an
interesting possibility that allows you to write functions that return not only multiple values, but
also an unknown number of values.
In this section, we’ll write the Statistics() function, similar to the CalculateStatistics()
function you saw a little earlier in this chapter. The Statistics() function returns the statistics in
an array. Moreover, it returns not only the average and the standard deviation, but the minimum
and maximum values in the data set as well. One way to declare a function that calculates all the
statistics is as follows:
Function Statistics(ByRef DataArray() As Double) As Double()
This function accepts an array with the data values and returns an array of Doubles. To imple-
ment a function that returns an array, you must do the following:
1. Specify a type for the function’s return value and add a pair of parentheses after the type’s
name. Don’t specify the dimensions of the array to be returned here; the array will be
declared formally in the function.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 116
116 CHAPTER 3 PROGRAMMING FUNDAMENTALS
2. In the function’s code, declare an array of the same type and specify its dimensions. If the
function should return four values, use a declaration like this one:
Dim Results(3) As Double
The Results array, which will be used to store the results, must be of the same type as the
function— its name can be anything.
3. To return the Results array, simply use it as an argument to the Return statement:
Return(Results)
4. In the calling procedure, you must declare an array of the same type without dimensions:
Dim Statistics() As Double
5. Finally, you must call the function and assign its return value to this array:
Stats() = Statistics(DataSet())
Here, DataSet is an array with the values whose basic statistics will be calculated by the
Statistics() function. Your code can then retrieve each element of the array with an index
value as usual.
VB 2008 at Work: The Statistics Project
The Statistics sample project demonstrates how to write a procedure that returns an array. When
you run it, the Statistics application creates a data set of random values and then calls the Statis-
tics() function to calculate the data set’s basic statistics. The results are returned in an array,
and the main program displays them in Label controls, as shown in Figure 3.3. Every time the
Calculate Statistics button is clicked, a new data set is generated and its statistics are displayed.
Figure 3.3
The Statistics project
calculates the basic
statistics of a data set
and returns them in an
array.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 117
ARGUMENTS 117
The Statistics() function’s code is based on the preceding discussion, and I will not show it
here. You can open the Statistics project and examine the function’s code, as well as how the main
program uses the array returned by the Statistics() function.
Overloading Functions
There are situations in which the same function must operate on different data types or a differ-
ent number of arguments. In the past, you had to write different functions, with different names
and different arguments, to accommodate similar requirements. The Framework introduced the
concept of function overloading, which means that you can have multiple implementations of
the same function, each with a different set of arguments and possibly a different return value.
Yet all overloaded functions share the same name. Let me introduce this concept by examining
one of the many overloaded functions that come with the .NET Framework.
The Next method of the System.Random class returns an integer value from –2,147,483,648 to
2,147,483,647. (This is the range of values that can be represented by the Integer data type.) We
should also be able to generate random numbers in a limited range of integer values. To emulate
the throw of a die, we want a random value in the range from 1 to 6, whereas for a roulette game
we want an integer random value in the range from 0 to 36. You can specify an upper limit for the
random number with an optional integer argument. The following statement will return a random
integer in the range from 0 to 99:
randomInt = rnd.Next(100)
You can also specify both the lower and upper limits of the random number’s range. The
following statement will return a random integer in the range from 1,000 to 1,999:
randomInt = rnd.Next(1000, 2000)
The same method behaves differently based on the arguments we supply. The behavior of the
method depends either on the type of the arguments, the number of the arguments, or both. As
you will see, there’s no single function that alters its behavior based on its arguments. There are as
many different implementations of the same function as there are argument combinations. All
the functions share the same name, so they appear to the user as a single multifaceted function.
Thesefunctionsareoverloaded,andyou’llseehow they’re implemented in the following section.
If you haven’t turned off the IntelliSense feature of the editor, as soon as you type the opening
parenthesis after a function or method name, you see a yellow box with the syntax of the function
or method. You’ll know that a function, or a method, is overloaded when this box contains a
number and two arrows. Each number corresponds to a different overloaded form, and you can
move to the next or previous overloaded form by clicking the two little arrows or by pressing the
arrow keys.
Let’s return to the Min() function we implemented earlier in this chapter. The initial imple-
mentation of the Min() function is shown next:
Function Min(ByVal a As Double, ByVal b As Double) As Double
Min = IIf(a < b, a, b)
End Function
By accepting Double values as arguments, this function can handle all numeric types. VB 2008
performs automatic widening conversions (it can convert Integers and Decimals to Doubles),Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 118
118 CHAPTER 3 PROGRAMMING FUNDAMENTALS
so this trick makes the function work with all numeric data types. However, what about strings?
If you attempt to call the Min() function with two strings as arguments, you’ll get an exception.
The Min() function just can’t handle strings.
To write a Min() function that can handle both numeric and string values, youmust, in essence,
write two Min() functions. All Min() functions must be pre?xed with the Overloads keyword.
The following statements show two different implementations of the same function:
Overloads Function Min(ByVal a As Double, ByVal b As Double) As Double
Min = Convert.ToDouble(IIf(a < b, a, b))
End Function
Overloads Function Min(ByVal a As String, ByVal b As String) As String
Min = Convert.ToString(IIf(a < b, a, b))
End Function
We need a third overloaded form of the same function to compare dates. If you call the Min()
function, passing as an argument two dates, as in the following statement, the Min() function will
compare them as strings and return (incorrectly) the ?rst date.
Debug.WriteLine(Min(#1/1/2009#, #3/4/2008#))
This statement is not even valid when the Strict option is on, so you clearly need another over-
loaded form of the function that accepts two dates as arguments, as shown here:
Overloads Function Min(ByVal a As Date, ByVal b As Date) As Date
Min = IIf(a < b, a, b)
End Function
If you now call the Min() function with the dates #1/1/2009# and #3/4/2008#, the function
will return the second date, which is chronologically smaller than the ?rst.
Let’s look into a more complicated overloaded function, which makes use of some topics dis-
cussed later in this book. The CountFiles() function counts the number of ?les in a folder that
meet certain criteria. The criteria could be the size of the ?les, their type, or the date they were
created. You can come up with any combination of these criteria, but the following are the most
useful combinations. (These are the functions I would use, but you can create even more combina-
tions or introduce new criteria of your own.) The names of the arguments are self-descriptive, so I
need not explain what each form of the CountFiles() function does.
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer) As Integer
CountFiles(ByVal fromDate As Date, ByVal toDate As Date) As Integer
CountFiles(ByVal type As String) As Integer
CountFiles(ByVal minSize As Integer, ByVal maxSize As Integer,
ByVal type As String) As Integer
CountFiles(ByVal fromDate As Date, ByVal toDate As Date,
ByVal type As String) As Integer
Listing 3.10 shows the implementation of these overloaded forms of the CountFiles() func-
tion. (I’mnot showing all overloaded forms of the function; you can open the OverloadedFunctions
project in the IDE and examine the code.) Because we haven’t discussed ?le operations yet, most
of the code in the function’s body will be new to you — but it’s not hard to follow. For the bene?tPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 119
ARGUMENTS 119
of readers who are totally unfamiliar with ?le operations, I included a statement that prints in the
Immediate window the type of ?les counted by each function. The Debug.WriteLine statement
prints the values of the arguments passed to the function, along with a description of the type of
search it will perform. The overloaded form that accepts two integer values as arguments prints
something like this:
You’ve requested the files between 1000 and 100000 bytes
whereas the overloaded form that accepts a string as an argument prints the following:
You’ve requested the .EXE files
Listing 3.10: The Overloaded Implementations of the CountFiles() Function
Overloads Function CountFiles(
ByVal minSize As Integer,
ByVal maxSize As Integer) As Integer
Debug.WriteLine(”You’ve requested the files between ” &
minSize & ” and ” & maxSize & ” bytes”)
Dim files() As String
files = System.IO.Directory.GetFiles(”c:\windows”)
Dim i, fileCount As Integer
Fori=0To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i))
If FI.Length >= minSize And FI.Length <= maxSize Then
fileCount = fileCount + 1
End If
Next
Return(fileCount)
End Function
Overloads Function CountFiles(
ByVal fromDate As Date,
ByVal toDate As Date) As Integer
Debug.WriteLine(”You’ve requested the count of files created from ” &
fromDate & ” to ” & toDate)
Dim files() As String
files = System.IO.Directory.GetFiles(”c:\windows”)
Dim i, fileCount As Integer
Fori=0To files.GetUpperBound(0)
Dim FI As New System.IO.FileInfo(files(i))
If FI.CreationTime.Date >= fromDate And
FI.CreationTime.Date <= toDate Then
fileCount = fileCount + 1
End If
Next
Return(fileCount)
End FunctionPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 120
120 CHAPTER 3 PROGRAMMING FUNDAMENTALS
Overloads Function CountFiles(ByVal type As String) As Integer
Debug.WriteLine(”You’ve requested the ” & type & ” files”)
‘ Function Implementation
End Function
Overloads Function CountFiles(
ByVal minSize As Integer,
ByVal maxSize As Integer,
ByVal type As String) As Integer
Debug.WriteLine(”You’ve requested the ” & type &
” files between ” & minSize & ” and ” &
maxSize & ” bytes”)
‘ Function implementation
End Function
Overloads Function CountFiles(ByVal fromDate As Date,
ByVal toDate As Date, ByVal type As String) As Integer
Debug.WriteLine(”You’ve requested the ” & type &
” files created from ” & fromDate & ” to ” & toDate)
‘ Function implementation
End Function
If you’re unfamiliar with the Directory and File objects, focus on the statement that prints to the
Immediate window and ignore the statements that actually count the ?les that meet the speci?ed
criteria. After reading Chapter 15, ‘‘Accessing Folders and Files,’’ you can revisit this example and
understand the statements that select the qualifying ?les and count them.
Start a new project and enter the de?nitions of the overloaded forms of the function on the
form’s level. Listing 3.10 is lengthy, but all the overloaded functions have the same structure and
differ only in how they select the ?les to count. Then place a TextBox and a button on the form, as
shown in Figure 3.4, and enter a few statements that exercise the various overloaded forms of the
function (such as the ones shown in Listing 3.11) in the button’s Click event handler.
Listing 3.11: Testing the Overloaded Forms of the CountFiles() Function
Private Sub Button1 Click(...) Handles Button1.Click
TextBox1.AppendText(CountFiles(1000, 100000) &
” files with size between 1KB and 100KB” & vbCrLf)
TextBox1.AppendText(CountFiles(#1/1/2006#, #12/31/2006#) &
” files created in 2006” & vbCrLf)
TextBox1.AppendText(CountFiles(”.BMP”) & ” BMP files” & vbCrLf)
TextBox1.AppendText(CountFiles(1000, 100000, ”.EXE”) &
” EXE files between 1 and 100 KB” & vbCrLf)
TextBox1.AppendText(CountFiles(#1/1/2006#, #12/31/2007#, ”.EXE”) &
” EXE files created in 2006 and 2007”)
End SubPetroutsos c03.tex V2 - 01/28/2008 1:01pm Page 121
THE BOTTOM LINE 121
Figure 3.4
The Overloaded
Functions project
The button calls the various overloaded forms of the CountFiles() function one after the other
and prints the results on the TextBox control. From now on, I’ll be omitting the list of arguments
in the most common event handlers, such as the Click event handler, because they’re always the
same and they don’t add to the readability of the code. In place of the two arguments, I’ll insert an
ellipsis to indicate the lack of the arguments.
Function overloading is used heavily throughout the language. There are relatively few func-
tions (or methods, for that matter) that aren’t overloaded. Every time you enter the name of a
function followed by an opening parenthesis, a list of its arguments appears in the drop-down list
with the arguments of the function. If the function is overloaded, you’ll see a number in front of
the list of arguments, as shown in Figure 3.5. This number is the order of the overloaded form
of the function, and it’s followed by the arguments of the speci?c form of the function. The ?gure
shows all the forms of the CountFiles() function.
Figure 3.5
The overloaded forms
of the CountFiles()
function
The BottomLine
Use Visual Basic’s ?ow-control statements. Visual Basic provides several statements for
controlling the sequence in which statements are executed: decision statements, which change
the course of execution based on the outcome of a comparison, and loop statements, which
repeat a number of statements while a condition is true or false.
Master It Explain brie?y the decision statements of Visual Basic.Petroutsos c03.tex V2 - 01/28/2008 1:01pm Page 122
122 CHAPTER 3 PROGRAMMING FUNDAMENTALS
Write subroutines and functions. To manage large applications, we break our code into
small, manageable units. These units of code are the subroutines and functions. Subroutines
perform actions and don’t return any values. Functions, on the other hand, perform calcula-
tions and return values. Most of the language’s built-in functionality is in the form of functions.
Master It How will you create multiple overloaded forms of the same function?
Pass arguments to subroutines and functions. Procedures and functions communicate with
one another via arguments, which are listed in a pair of parentheses following the procedure’s
name. Each argument has a name and a type. When you call the procedure, you must supply
values for each argument and the types of the values should match the types listed in the pro-
cedure’s de?nition.
Master It Explain the difference between passing arguments by value and passing
arguments by reference.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 123
Chapter 4
GUI Design and Event-Driven
Programming
The ?rst three chapters of this book introduced you to the basics of designing applications with
Visual Studio 2008 and the components of the Visual Basic language. You know how to design
graphical user interfaces (GUI) and how to use the statements of Visual Basic to program the
events of the various controls. You also know how to write functions and subroutines and how to
call the built-in functions and subroutines of Visual Basic.
In this chapter, you’ll design a few more Windows applications — this time, a few practical
applications with more functional interfaces and a bit of code that does something more practical.
You’ll put together the information presented so far in the book by building Windows applica-
tions with the visual tools of Visual Studio and you’ll see how the application interacts with users
by coding the events of interest. If you are new to Visual Studio, you should design the examples
on your own using the instructions in the text, rather than open the same projects and look at
the code.
In this chapter, you will learn how to do the following:
? Design graphical user interfaces
? Program events
? Write robust applications with error handling
OnDesigningWindowsApplications
As you recall from Chapter 1, ‘‘Getting Started with Visual Basic 2008,’’ the design of a Windows
application consists of two distinct phases: the design of the application’s interface and the cod-
ing of the application. The design of the interface is performed with visual tools and consists of
creating a form with the relevant elements. These elements are the building blocks of Windows
applications and are called controls.
The available controls are shown in the Toolbox and are the same elements used by all Win-
dows applications. In addition to being visually rich, the controls embed a lot of functionality. The
TextBox control, for example, can handle text on its own, without any programming effort on your
part. The ComboBox control expands the list with its items when users click the arrow button and
displays the selected item in its edit box. In general, the basic functionality of the controls is built
into the controls by design, so that all applications maintain a consistent look.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 124
124 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
The interface dictates how users will interact with your application. To prompt users for text or
numeric data, use TextBox controls. When it comes to specifying one or more of several options,
you have many choices: You can use a ComboBox control from which users can select an option,
or a few CheckBox controls on the form that users can select or clear. If you want to display a small
number of mutually exclusive options, place a few RadioButton controls on the form. Every time
the user selects an option, the previously selected one is cleared. To initiate actions, place one or
more Button controls on the form.
Controls expose a large number of properties, which are displayed in the Properties window at
design time. You use these properties to adjust not only the appearance of the controls on the form,
but their functionality as well. The process of designing the interface consists mostly of setting the
properties of the various controls.
An important aspect of the design of your application’s user interface is the alignment of the
controls on the form. Controls that are next to one another should be aligned horizontally. Controls
that are stacked should have either their left or right edges aligned vertically. You should also
make sure that the controls are spaced equally. The integrated development environment (IDE)
provides all the tools for sizing, aligning, and spacing controls on the form, and you’ll see these
tools in action through examples in this chapter.
After you have designed the interface, you know how your application will interact with the
user. The next step is to actually implement the interaction by writing some code. The program-
ming model of Visual Basic is event-driven: As the user interacts with the controls on your form,
some code is executed in response to user actions. The user’s actions cause events, and each con-
trol recognizes its own set of events and handles them through subroutines, which are called event
handlers.When users click a button, the control’s Click event is ?red, and you must insert the rele-
vant code in the control’s Click event handler. The event-driven programming model has proven
very successful, because it allows developers to focus on handling speci?c actions. It allows you to
break a large application into smaller, manageable units of code and implement each unit of code
independently of any other.
Developing Windows applications is a conceptually simple process, but there’s a methodol-
ogy to it and it’s not trivial. Fortunately, the IDE provides many tools to simplify the process;
it will even catch most of the errors in your code as you type. You have seen how to use some
of the tools of the IDE in the ?rst three chapters. In this chapter, I’ll present these tools through
examples.
Building a Loan Calculator
One easy-to-implement, practical application is a program that calculates loan parameters. Visual
Basic provides built-in functions for performingmany types of ?nancial calculations, and you need
only a single line of code to calculate the monthly payment given the loan amount, its duration,
and the interest rate. Designing the user interface, however, takes much more effort.
Regardless of the language you use, you must go through the following process to develop an
application:
1. Decide what the application will do and how it will interact with the user.
2. Design the application’s user interface according to the requirements of step 1.
3. Write the actual code behind the events you want to handle.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 125
BUILDING A LOAN CALCULATOR 125
Understanding How the Loan Calculator Application Works
Following the ?rst step of the process outlined previously, you decide that the user should be able
to specify the amount of the loan, the interest rate, and the duration of the loan in months. You
must, therefore, provide three text boxes in which the user can enter these values.
Another parameter affecting the monthly payment is whether payments are made at the begin-
ning or at the end of each month, so you must also provide a way for the user to specify whether
the payments will be early (?rst day of the month) or late (last day of the month). The most appro-
priate type of control for entering Yes/No or True/False type of information is the CheckBox
control. This control is a toggle: If it’s selected, you can clear it by clicking it; if it’s cleared, you can
select it by clicking again. The user doesn’t enter any data in this control (which means you need
not anticipate user errors with this control), and it’s the simplest method for specifying values
with two possible states.
Figure 4.1 shows a user interface that matches our design speci?cations. This is the main form
of the LoanCalculator project, which you will ?nd in this chapter’s folder on the book’s project
download site.
Figure 4.1
LoanCalculator is a sim-
ple ?nancial application.
The user enters all the information on the form and then clicks the Monthly Payment button to
calculate the monthly payment. The program will calculate the monthly payment and display it in
the lower TextBox control. All the action takes place in the button’s Click subroutine.
To calculate the monthly payments on a loan, we call the Pmt () built-in function, whose syntax
is the following:
MonthlyPayment = Pmt(InterestRate, Periods, Amount, FutureValue, Due)
The interest rate, argument InterestRate, is speci?ed as a monthly rate. If the yearly inter-
est rate is 16.5 percent, the value entered by the user in the Interest Rate box should be 14.5,
and the monthly rate will be 0.145/12. The duration of the loan, the Periods argument, isPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 126
126 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
speci?ed in number of months, and the Amount argument is the loan’s amount. The FutureValue
argument is the value of the loan at the end of the period, which should be zero (it would be a
positive value for an investment), and the last argument, Due, speci?es when payments are due.
The value of Due can be one of the constants DueDate.BegOfPeriod and DueDate.EndOfPeriod.
These two constants are built into the language, and you can use them without knowing their
exact value.
The present value of the loan is the amount of the loan with a negative sign. It’s negative
because you don’t have the money now. You’re borrowing it — it is money you owe to the bank.
Future value represents the value of something at a stated time — in this case, what the loan will
be worth when it’s paid off. This is what one side owes the other at the end of the speci?ed period.
So the future value of a loan is zero.
You don’t need to know how the Pmt () function calculates the monthly payment, just how
to call it and how to retrieve the results. To calculate the monthly payment on a loan of $25,000
with an interest rate of 14.5 percent, payable over 48 months, and payments due the last day
of the payment period (which in our case is a month), you’d call the Pmt() function as
follows:
Pmt(0.145 / 12, 48, -25000, 0, DueDate.EndOfPeriod)
The Pmt() function will return the value 689.448821287218. Because it’s a dollar amount, we
must round it to two decimal digits on our interface.Notice the negative sign in front of the Amount
argument in the statement. If you specify a positive amount, the result will be a negative payment.
The payment and the loan’s amount have different signs because they represent different cash
?ows. The loan’s amount is money you owe to the bank, whereas the payment is money you pay
to the bank.
The last two arguments of the Pmt() function are optional. If you omit them, Visual Basic uses
their default values, which are 0 for the FutureValue argument and DueDate.BegOfPeriod for
the Due argument. You can entirely omit these arguments and call the Pmt() function like this:
Pmt(0.145 / 12, 48, -25000)
Calculating the amount of the monthly payment given the loan parameters is quite
simple. What you need to understand are the parameters of a loan and how to pass them to
the Pmt() function. You must also know how the interest rate is speci?ed to avoid invalid val-
ues. Although the calculation of the payment is trivial, designing the interface will take a bit
of effort.
Designing the User Interface
Now that you know how to calculate the monthly payment, you can design the user interface. To
do so, start a new project, name it LoanCalculator, and rename its form to frmLoan.Your?rst
task is to decide the font and size of the text you’ll use for the controls on the form. The form is
the container of the controls, and they inherit some of the form’s properties, such as the font. You
can change the font later during the design, but it’s a good idea to start with the right font. At anyPetroutsos c04.tex V3 - 01/28/2008 12:36pm Page 127
BUILDING A LOAN CALCULATOR 127
rate, don’t try to align the controls if you’re planning to change their fonts. The change will, most
likely, throw off your alignment efforts.
The book’s sample project uses the 10-point Verdana font. To change it, select the form with
the mouse, double-click the name of the Font property in the Properties window to open the Font
dialog box, and select the desired font and attributes. I’m using the Verdana and Seago fonts a lot
because they’re clean and theywere designed for viewing onmonitors. Of course, this is a personal
choice. Avoid elaborate fonts and don’t mix different fonts on the same form (or in different forms
of the same application).
To design the form shown in Figure 4.1, follow these steps:
1. Place four labels on the form and assign the following captions (the Text property of each
control) to them:
Name Text
Label1 Amount
Label2 Duration
Label3 Interest Rate
Label4 Monthly Payment
You don’t need to change the default names of the four Label controls on the form because
their captions are all we need. You aren’t going to program them.
2. Place a TextBox control next to each label. Set their Name and Text properties to the follow-
ing values. I used meaningful names for the TextBox controls because we’ll use them in our
code shortly to retrieve the values entered by the user on these controls. These initial values
correspond to a loan of $25,000 with an interest rate of 14.5 percent and a payoff period of
48 months.
Name Text
txtAmount 25000
txtDuration 48
txtRate 14.5
txtPayment
3. The fourth TextBox control is where the monthly payment will appear. The user isn’t
supposed to enter any data in this box, so youmust set its ReadOnly property to True to lock
the control. You’ll be able to change its value fromwithin your code, but users won’t be able
to type anything in it. (We could have used a Label control instead, but the uniform look of
TextBoxes on a formis usually preferred.) Youwill also notice that the TextBox controls have
a 3D frame. Experiment with the control’s BorderStyle property to discover the available
styles for the control’s frame (I’ve used the Fixed3D setting for the TextBox controls).Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 128
128 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING
4. Next, place a CheckBox control on the form. By default, the control’s caption is CheckBox1,
and it appears to the right of the check box. Because we want the titles to be to the left of the
corresponding controls, we’ll change this default appearance.
5. Select the check box with the mouse, and in the Properties window locate the CheckAlign
property. Its value is MiddleLeft. If you expand the drop-down list by clicking the arrow
button, you’ll see that this property has many different settings, and each setting is shown
as a square. Select the button that will center the text vertically and right-align it hori-
zontally. The string MiddleRight will appear in the Properties window when you click the
appropriate button.
6. With the check box selected, locate the Name property in the Properties window, and set it
to chkPayEarly.
7. Change the CheckBox’s caption by entering the string Early Payment in its Text property
?eld.
8. Place a Button control in the bottom-left corner of the form. Name it bttnShowPayment,and
set its Text property to Monthly Payment.
9. Finally, place another Button control on the form, name it bttnExit,andsetits Text prop-
erty to Exit.Petroutsos c04.tex V3 - 01/28/2008 12:36pm Page 129 

Make a Free Website with Yola.