Flylib.com

Books Software

 
 
 

Section 3.2. Declaring Variables and Constants

   

3.2 Declaring Variables and Constants

A variable declaration is an association of a variable name with a data type. In and of itself, this does not imply variable creation. However, for nonobject variables, a variable declaration does create a variable. A declaration such as:

Dim


x


As Integer

creates an Integer variable named x . We can also write:

Dim x As Integer = New Integer(  )

which emphasizes the role of the constructor function for the Integer data type. (The constructor is the function that VB.NET uses to create the variable.)

When multiple variables are declared on the same line, if a variable is not declared with an explicit type declaration, then its type is that of the next variable with an explicit type declaration. Thus, in the line:

Dim x As Long,


i


,


j


,


k


As Integer, s As String

the variables i , j , and k have type Integer. (In VB 6, the variables i and j would have type Variant, which is VB 6's default data type.)

VB.NET permits the initialization of variables in the same line as their declaration (at long last!). Thus, we may write:

Dim x As Integer = 5

to declare an Integer variable and initialize it to 5. Similarly, we can declare and initialize more than one variable on a single line:

Dim x As Integer = 6, y As Integer = 9

Note that in this case, each variable that you declare must explicitly be assigned a data type. You cannot assign each variable an explicit value without explicitly declaring the data type of each variable.

Object variables are declared in the same manner:

Dim obj As MyClass

However, this declaration does not create an object variable, and the variable is equal to Nothing at this point. Object creation requires an explicit call to the object's constructor, as in:

Dim obj As New MyClass(  )

or:

Dim obj As MyClass = New Myclass(  )

or:

Dim obj As MyClass

obj = New MyClass(  )

Variables and constants can be declared with any of the following access modifiers :

  • Public

  • Private

  • Friend

  • Protected

  • Protected Friend

Note also that the Dim keyword can be used as well, but it often defaults to one of the previously mentioned access modifiers. This is potentially confusing, so the Dim keyword should be used only when required, as it is for local variables.

Access modifiers help to specify the scope and accessibility of the variable. We discuss the meaning of these access variables in detail in Chapter 4.

Constant declarations are analogous to variable declarations and have the form:



AccessModifier


Const Name As Type = Value

where AccessModifier is one of the access modifiers defined earlier. Note that when Option Strict is On (the default), all constant declarations must have a declared type.

   
   

3.3 Data Types

The .NET Common Language Runtime (CLR) includes the Common Type System (CTS), which defines the data types that are supported by the CLR. Thus, each of the languages in the .NET Framework (VB, C#, JScript, and Managed C++) implements a subset of a common set of data types. We say subset because, unfortunately , not all of the CTS types are implemented by VB.NET. For instance, the CTS includes some unsigned integer data types that are not implemented in VB.

As an aside, it is possible to use the VB-unsupported data types in VB by direct use of the corresponding Framework Class Library class. Here is an example illustrating the ability to use the unsigned 16-bit integer data type, whose range of values is 0 to 65,535. Note the use of the ToUInt16 method of the Convert class to actually get an unsigned 16-bit integer:

Dim ui As UInt16

ui = Convert.ToUInt16(65535)

MsgBox(ui.ToString)

Thus, the native VB data types are wrappers for the CTS data types. To illustrate , the VB Integer data type is a wrapper for the Int32 structure that is part of the .NET Framework's System namespace. One of the members of the Int32 structure is MaxValue, which returns the maximum value allowed for this data type. Thus, even though MaxValue is not officially part of VB.NET (nor is it mentioned in the VB documentation), we can write:

Dim i As Integer

MsgBox(i.Maxvalue)   ' Displays 2147483647

3.3.1 Value and Reference Types

The types defined in the CTS fall into three categories:

  • Value types

  • Reference types

  • Pointer types

However, pointer types are not implemented in VB, so we will not discuss these types.

The difference between value and reference types is how variables of the corresponding type represent that type. When a value-type variable is defined, as in:

Dim int As Integer = 5

a memory location is set aside to hold the actual data (in this case the number 5). In contrast, when a reference-type variable is defined, as in:

Dim


obj


As New CEmployee

the VB compiler creates the object in memory, but then sets the variable obj to a 4-byte memory location that contains the address of the object.

In short, value-type variables contain the data, whereas reference-type variables point to the data.

The distinction between value type and reference type has several consequences, one of which is in the way assignments work. To illustrate, consider the following class, which has a single property:

Public Class MyClass

    Public Age As Short

End Class

and the structure MyStruct , also with a single property:

Structure MyStruct

    Public Age As Short

End Structure

Classes are reference types, whereas structures are value types. Now consider the following code, which is thoroughly commented:

' Declare two class variables and two structure variables.

Dim objRef1 As MyClass

Dim objRef2 As MyClass

Dim objValue1 As MyStruct

Dim objValue2 As MyStruct



' Instance the class.

objRef1 = New MyClass(  )

' Set the Age property to 20.

objRef1.Age = 20

' Set the second variable to the first variable.

' This is an equating of object *references* because

' classes are reference types.

objRef2 = objRef1

' Set the Age property of objRef2 to 30.

objRef2.Age = 30

' Check the values of the Age property.

Debug.WriteLine(objRef1.Age)

Debug.WriteLine(objRef2.Age)



' Do the same thing with the structure



' Instance the structure.

objValue1 = New MyStruct(  )

' Set the Age property to 20.

objValue1.Age = 20

' Set the second variable to the first variable.

' This is an equating of object *values* because

' structures are value types.

objValue2 = objValue1

' Set the Age property of objValue2 to 30.

objValue2.Age = 30

' Check the values of the Age property.

Debug.Writeline(objValue1.Age)

Debug.Writeline(objValue2.Age)

Now, the output is:

30

30

20

30

To understand what is happening, we need to realize that the reference assignment:

objRef2 = objRef1

sets both variables to the same value. But that value is the address of the object, and so both variables point to the same object. Hence, when we change the Age property using the second variable, this change is also reflected in the first variable.

On the other hand, the value assignment:

objValue2 = objValue1

causes a second structure to be created, setting the new structure's properties to the same value as the original structure. Thus, changing one structure's Age property does not affect the other structure's Age property.

Note that the VB Array type is also a reference type. To illustrate, consider the following code:

Dim iArray1(  ) As Integer = {1, 2, 3}

Dim iArray2(  ) As Integer



iArray2 = iArray1

iArray1(0) = 100

msgbox(iArray2(0))

The message box displays 100, indicating that both array variables point to the same array.

The String data type is a reference type, implemented by the String class. However, it has some characteristics of a value type. To illustrate, consider the following code:

Dim s1, s2 As String

s1 = "String 1"

s2 = s1

s2 = "String 2"

MsgBox(s1)

Since this is a reference type, we would expect the last line to produce the message "String 2" , but instead we get "String 1" . The reason can be found in Microsoft's documentation:

An instance of String is "immutable" because its value cannot be modified once it has been created. Methods that appear to modify a String actually return a new instance of String containing the modification.

Thus, the code:

s2 = s1

points s2 to the same string as s1, as is usual with reference types. Then the attempt to modify the string in the code:

s2 = "String 2"

does not produce the expected result because strings are immutable. Instead, we get a new string pointed to by s2, while s1 retains its value.

The following code supports this conclusion:

Dim s1, s2 As String

s1 = "String 1"

' s2 poitns to same string as s1

s2 = s1

' Show s2 before any changes to the string

MsgBox(s2)      ' Displays "String1"

' Change the string

s2 = "String 2"

' Set s1 to Nothing

s1 = Nothing

' Now s1 is nothing and displays accordingly

MsgBox(s1)      ' Displays nothing

' s2 is a new string 

MsgBox(s2)      ' Displays "String 2"

Enjoy!

3.3.2 VB Data Types: A Summary

The following lists the data types supported by VB.NET, along with their underlying .NET type, storage requirements, and range of values:

Boolean

.NET CTS type: System.Boolean

Type: Value (Structure)

Storage: 2 bytes

Value range: True or False

Byte

.NET CTS type: System.Byte

Type: Value (Structure)

Storage: 1 byte

Value range: 0 to 255 (unsigned)

Char

.NET CTS type: System.Char

Type: Value (Structure)

Storage: 2 bytes

Value range: A character code from 0 to 65,535 (unsigned)

Date

.NET CTS type: System.DateTime

Type: Value (Structure)

Storage: 8 bytes

Value range: January 1, 1 CE to December 31, 9999

Decimal

.NET CTS type: System.Decimal

Type: Value (Structure)

Storage: 12 bytes

Value range: +/-79,228,162,514,264,337,593,543,950,335 with no decimal point; +/-7.9228162514264337593543950335 with 28 places to the right of the decimal; smallest nonzero number is +/-0.0000000000000000000000000001

Double (double-precision floating point)

.NET CTS type: System.Double

Type: Value (Structure)

Storage: 8 bytes

Value range: -1.79769313486231E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values

Integer

.NET CTS type: System.Int32

Type: Value (Structure)

Storage: 4 bytes

Value range: -2,147,483,648 to 2,147,483,647

Long (long integer)

.NET CTS type: System.Int64

Type: Value (Structure)

Storage: 8 bytes

Value range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Object

.NET CTS type: System.Object

Type: Reference (Class)

Storage: 4 bytes

Value range: Any type can be stored in an Object variable.

Short

.NET CTS type: System.Int16

Type: Value (Structure)

Storage: 2 bytes

Value range: -32,768 to 32,767

Single (single precision floating point)

.NET CTS type: System.Single

Type: Value (Structure)

Storage: 4 bytes

Value range: -3.402823E38 to -1.401298E-45 for negative values; 1.401298E-45 to 3.402823E38 for positive values

String (variable-length)

.NET CTS type: System.String

Type: Reference (Class)

Storage: 10 bytes + (2 * string length)

Value range: 0 to approximately 2 billion Unicode characters

User -Defined Type (structure)

.NET CTS type: (inherits from System.ValueType)

Type: Value (Structure)

Storage: Sum of the sizes of its members

Value range: Each structure member has range determined by its data type and is independent of the ranges of the other members.

Note that the CTS data types are either structures (which are value types) or classes (which are reference types) and are located within the .NET System namespace.

3.3.3 Simple Data Types in Visual Basic

In this section, we discuss data types in general and VB.NET data types in particular.

Simple data types can be classified into groups as follows . Note that these groups are not mutually exclusive:

Numeric data type

A data type in which the underlying set is a set of numbers and for which the set of operations includes the arithmetic operations.

Integer data type

A numeric data type in which the underlying set is a set of integers. (As we will see, VB has several integer data types.)

Floating-point data type

A noninteger data type whose underlying set is a subset of the rational numbers.

Boolean data type

A data type whose underlying set has size 2. This set is usually thought of as { True , False }.

Character data type

A data type whose underlying set is a set of characters. Of course, each value must be represented in memory as a binary string, which can also be interpreted as a number. Nevertheless, this interpretation is not part of a character data type.

Let us consider the Visual Basic .NET data types individually.

3.3.3.1 Boolean data type

The Boolean is a 16-bit data type that can only represent two values: True and False . The VB keywords True and False are used to assign these values to a Boolean variable.

When a numeric value is converted to Boolean, any nonzero value is converted to True , and zero is converted to False . In the other direction, False is converted to zero, and True is converted to -1. (Incidentally, in C, C#, and C++, True is converted to 1. This change was made in Beta 1 of VB.NET to bring it in line with the other languages, but was subsequently changed back in Beta 2.)

The underlying .NET data type for Boolean is System.Boolean.

3.3.3.2 Byte data type

The Byte data type is an 8-bit unsigned data type whose range is the set of integers from 0 to 255. According to the documentation, the Byte data type "is used for containing binary data." Since ordinary arithmetic operations can be used with Byte variables, the data type is, in this sense, an integer data type. Also, there do not appear to be any special operators, such as shift operators, that would give the type a "binary data" flavor. Oh well.

The underlying .NET data type for Byte is System.Byte.

3.3.3.3 Char data type

The Char data type is a 16-bit character data type with a character code ranging from 0 to 65,535, which represent a single Unicode character. As a data type, Char is new to VB.NET; there was no equivalent in previous versions of Visual Basic.

It is important not to confuse the Char and String data types. (We discuss this data type in Section 3.3.3.12.) A string consisting of a single character is not the same as a Char. To illustrate, consider defining a new string and initializing it to a sequence consisting of a repeated single character, for example, "AAAAA." In earlier versions of VB, this was done as follows:

Dim s As String

s = String$(5, "A")

In VB.NET, this is done using the String class constructor, which has the syntax:

Dim variable As New String(Character, Integer)

If we turn strict type checking on with the Option Strict On statement, the code:

Dim s As New String("A",5)

produces the error message, "Option Strict disallows implicit conversions from String to Char."

To get a Char, we must append a c to the end of the string literal. Thus, the following works:

Dim s As New String("A"c, 5)

The underlying .NET data type for Char is System.Char.

3.3.3.4 Date data type

Date values are stored as IEEE 64-bit long integers that can represent dates in the range January 1, 0001 to December 31, 9999 (which should be plenty), and times from 0:00:00 to 23:59:59.

Literal strings must be enclosed in number signs (#) to be recognized as dates. The VB.NET compiler changes date formats automatically. For instance, if we enter the code:

Dim d As Date

d = #November 9, 1948#

Msgbox(d)

the compiler changes the second line to:

d = #11/9/1948#

or whatever the regional settings on the host system dictate . The .NET equivalent of Date is System.DateTime.

3.3.3.5 Decimal data type

Values of the Decimal data type are stored as 96-bit (12-byte) signed integers, along with an internal scale factor ranging from 0 to 28, which is applied automatically when we set a value for a Decimal variable. This allows us to enter values from a number of different ranges.

For instance, we can use integers (no decimal part) in the range:

+/-79,228,162,514,264,337,593,543,950,335

in which case the scale factor is set to 0. On the other extreme, we can use values in the range:

-7.9228162514264337593543950335 to -0.0000000000000000000000000001

on the negative side, or:

0.0000000000000000000000000001 to 7.9228162514264337593543950335

on the positive side. In this case, the scale factor is set to 28.

To write a literal Decimal, append a D , as in:

123456.789D

The type identifier for Decimal is the symbol @ , as in:

Dim dec@

The underlying .NET data type for Decimal is System.Decimal. This class has some useful members, such as MaxValue and MinValue, which give the maximum and minimum values of the decimal type.

By the way, in previous versions of VB, the Decimal existed only as a Variant data subtype ” there were no variables of type Decimal.

3.3.3.6 Double data type

Values of type Double are IEEE 64-bit (8-byte) floating-point numbers with the range:

-1.79769313486231E308 to -4.94065645841247E-324

on the negative side, and:

4.94065645841247E-324 to 1.79769313486232E308

on the positive side.

To write a literal Double, we must append an R , as in:

12345.678R

The type identifier for a Double is # , as in:

Dim dbl#

The underlying .NET data type for Double is System.Double.

3.3.3.7 Integer data type

The Integer data type is a 32-bit data type that stores signed integers ranging from:

-2^31 to 2^31-1

or:

-2,147,483,648 to 2,147,483,647

Note that this is the native word size on a 32-bit processor, and so the Integer data type provides superior performance as compared to integer data types of other sizes.

Note also that this data type size is new for VB.NET. In VB 6 and earlier, the Integer data type was a 16-bit data type.

To define a literal Integer, append an I , as in:

123I

The Integer type identifier is the percent sign (%), as in:

Dim int%

The underlying .NET data type for Integer is System.Int32.

3.3.3.8 Long data type

The Long data type is a 64-bit integer data type that stores signed integers ranging from:

-2^63 to 2^63-1

or:

-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Note that this data type size is new for VB.NET. In VB 6 and earlier, the Long data type was a 32-bit data type.

To define a literal Long, append an L , as in:

123L

The Long type identifier is the ampersand sign ( & ), as in:

Dim lng&

The underlying .NET data type for Long is System.Int64.

3.3.3.9 Object data type

The Object data type is a pointer data type. That is, a value of type Object is an address that references the object in memory. In VB.NET, the Object data type is the universal data type; an Object variable can refer to (point to) data of any other data type. For instance, the following code places a Long value in an Object variable:

Dim obj As Object

obj = 123L

The underlying .NET data type for Object is System.Object.

It is worth noting that when we use variables of type Object, we do pay a performance penalty because VB.NET cannot bind the object's method invocations to the actual method code until runtime. This is referred to as late binding . On the other hand, declaring variables of a specific object type allows early binding at compile time, which is much more efficient. Thus, code such as:

Dim obj As Object

. . .

obj.AMethod

is much less efficient than:

Dim obj As System.Data.DataSet

. . .

obj.AMethod

We revisit this issue in more detail later in this chapter.

As we have seen, the Object data type is universal. Just as in VB 6, in which you can use the VarType function to determine the data subtype of a Variant, in VB.NET you can use the VarType function to determine the data subtype of an object.

In addition, the Object class in the Framework Class Library's System namespace has a method named GetType that returns an object of type Type. Thus, if obj is a variable of type Object, then the code:

obj.GetType

returns a Type object. In turn, the Type class, which is also a member of the Framework Class Library's System namespace, has two methods that return information about the subtype of the object:

  • ToString returns a string that describes the subtype of the data. It is roughly equivalent to calling the VB.NET TypeName function, except that the former method uses the data type name from the .NET Framework Class Library, whereas the latter function uses the Visual Basic name .

  • GetTypeCode returns an enumeration value from the TypeCode enumeration. It is roughly equivalent to calling the VB6 VarType function, which, as we have said, is no longer supported in VB.NET.

For reference, the following code generates the values in Table 3-1:

Dim obj As Object

obj = ???

debug.write(obj.GetType.ToString)

Debug.Write(TypeName(obj))

debug.writeline(Type.GetTypeCode(obj.GetType))
Table 3-1. Values of ToString and GetTypeCode

obj = ???

ToString

TypeName

GetType

obj = True

System.Boolean

Boolean

3

obj = CByte(100)

System.Byte

Byte

6

obj = #1/1/2000#

System.DateTime

Date

16

obj = CDec(100)

System.Decimal

Decimal

15

obj = CDbl(100)

System.Double

Double

14

obj = CInt(100)

System.Int32

Integer

9

obj = CLng(100)

System.Int64

Long

11

obj = CShort(100)

System.Int16

Short

7

obj = CSng(100)

System.Single

Single

13

obj = "Donna"

System.String

String

18

3.3.3.10 Short data type

The Short data type is a 16-bit integer data type that stores signed integers ranging from:

-2^15 to 2^15-1

or:

-32,768 to 32,767

Note that in earlier versions of Visual Basic, the Short data type is called the Integer data type.

To define a literal Short, append an S , as in:

123S

The underlying .NET data type for Short is System.Int16.

3.3.3.11 Single data type

Values of type Single are IEEE 32-bit (4-byte) floating-point numbers with the range:

-3.402823E38 to -1.401298E-45

on the negative side, and:

1.401298E-45 to 3.402823E38

on the positive side.

To write a literal Single, we must append an F (for floating point), as in:

12345.678F

The type identifier for a Single is an exclamation point ( ! ), as in:

Dim sng!

The underlying .NET data type for Single is System.Single.

3.3.3.12 String data type

The String data type represents Unicode strings of up to approximately 2 billion characters. The type identifier for the string data type is a dollar sign ( $ ). The underlying .NET data type for this type is System.String.

To create a new string, we can declare a variable and assign it a string as follows:

Dim sName As String

sName = "Donna"

or equivalently, in one statement:

Dim sName As String = "Donna"

The type identifier for a String is a dollar sign ( $ ), as in:

Dim str$
3.3.3.13 Structure data type: user-defined types

In VB.NET, the Structure type is a powerful data type that has many properties in common with classes.

To declare a structure, we use the Structure statement, whose syntax is:

[PublicPrivateFriend] Structure StructureName

   Nonmethod member declarations

   Method member declarations

End Structure

The members of a structure can be variables, properties, methods, or events. Note, however, that each member must be declared with an access modifier: Public (or Dim ), Private , or Friend .

The simplest and most common use of structures is to encapsulate related variables. For instance, we might define a structure as follows:

Structure strPerson

    Public Name As String

    Public Address As String

    Public City As String

    Public State As String

    Public Zip As String

    Public Age As Short

End Structure

To define a variable of type strPerson , we write (as usual):

Dim APerson As strPerson

To access a member of a structure, we use the dot syntax, as in:

APerson.Name = "Beethoven"

Note that structure members can be other structures or other objects. Structures can also be passed as arguments to functions, or as the return type of a function.

As mentioned, structures are similar to classes. For instance, consider the following structure:

Structure strTest

    ' A public nonmethod member

    Public Name As String

    ' A private member variable

    Private msProperty As String

    ' A public method member

    Public Sub AMethod(  )

        Msgbox("Structure method. Property is: " & msProperty)

    End Sub

    ' A public property member

    Public Property AProperty(  ) As String

        Get

            AProperty = msProperty

        End Get

        Set

            msProperty = Value

        End Set

    End Property

End Structure

Now we can set the structure's property and invoke its method as follows:

Dim str As strTest

str.AProperty = "Donna"

str.AMethod(  )

Although structures are similar to classes, they do not support the following class features:

  • Structures cannot explicitly inherit, nor can they be inherited.

  • All constructors for a structure must be parameterized.

  • Structures cannot define destructors.

  • Member declarations cannot include initializers nor can they use the As New syntax or specify an initial array size.

For a reference to the object-oriented terminology, see Chapter 4.

3.3.4 Data Type Conversion

The process of converting a value of one data type to another is called conversion or casting . A cast operator can be applied to a literal value or to a variable of a given type. For instance, we have:

Dim lng As Long

Dim int As Integer = 6

' Cast an Integer variable to a Long

lng = CLng(Int)

' Cast a literal integer to a Long

lng = CLng(12)

A cast can be widening or narrowing. A widening cast is one in which the conversion is to a target data type that can accommodate all values in the source data type, such as casting from Short to Integer or Integer to Double. In such a case, no data is ever lost, and the cast will not generate an error. A narrowing cast is one in which the target data type cannot accommodate all values in the source data type. In this case, data may be lost, and the cast may not succeed.

Under VB.NET, conversions are made in two ways: implicitly and explicitly. An implicit conversion is done by the compiler when circumstances warrant it (and if it is legal). For instance, if we write:

Dim lng As Long

lng = 54

then the compiler casts the Integer 54 as a Long.

The type of implicit conversion that the compiler will do depends in part on the setting of the Option Strict value. For instance, if Option Strict is On, only widening casts can be implicit; so then the following code:

Dim b As Boolean

b = "True"

generates a type conversion error, whereas if we add the line:

Option Strict Off

to the beginning of the module, then the previous code executes without error.

Explicit conversion requires explicitly calling a conversion function (or cast operator). The type conversion functions supported by VB.NET all have the form:

C


name


(


expression


)

where expression is an expression that is in the range of the target data type. Specifically, we have the following conversion functions:

CBool

Converts any valid String or numeric expression to Boolean. When a numeric value is converted to Boolean, any nonzero value is converted to True , and zero is converted to False .

CByte

Converts any numeric expression in the range 0 to 255 to Byte, while rounding any fractional part.

CChar

Takes a string argument and returns the first character of the string as a Char data type.

CDate

Converts any valid representation of a date or time to Date.

CDbl

Converts any expression that can be evaluated to a number in the range of a Double to Double.

CDec

Converts any expression that can be evaluated to a number in the range of a Decimal to Decimal.

CInt

Converts any numeric expression in the range of Integer (-2,147,483,648 to 2,147,483,647) to Integer, while rounding any fractional part.

CLng

Converts any expression that can be evaluated to a number in the range of a Long to Long, while rounding any fractional part.

CObj

Converts any expression that can be interpreted as an object to Object. For instance, the code:

Dim obj As Object


obj


= CObj("test")

casts the string "test" to type Object and places it in the Object variable obj .

CShort

Converts any numeric expression in the range -32,768 to 32,767 to Short, while rounding any fractional part.

CSng

Converts any expression that can be evaluated to a number in the range of a Single to Single. If the numeric expression is outside the range of a Single, an error occurs.

CStr

If the expression input to CStr is Boolean, the function returns one of the strings "True" or "False." For an expression that can be interpreted as a date, the return value is a string representation of that date, in the date format defined by the regional settings of the host computer. For a numeric expression, the return value is a string representing the number.

CType

A general-purpose conversion function, CType has the following syntax:

CType(


expression


,


typename


)

where expression is an expression or variable, and typename is the data type to which it will be converted. The function supports conversions to and from the standard data types, as well as to and from object data types, structures, and interfaces.