Previous section   Next section

3.2 VB.NET Types

Visual Basic .NET can (and should) be treated as a strongly typed language. In a strongly typed language you must declare the type of each object you create (e.g., Integer, Decimal, String, Window, Button, etc.) and the compiler will help you prevent bugs by enforcing that only data of the right type is assigned to those objects. You tell the compiler you want Visual Basic .NET to be strongly typed by adding the line:

Option Strict On

to the top of every source code file. While this is optional it is good programming practice, and this book will assume that Option Strict is set On from now on. You can make this the default in Visual Studio .NET (starting in Version 1.1.) by choosing the menu items Tools->Options->Projects->VB Defaults and setting the default to Option Strict On.

The type of an object signals to the compiler the size of that object (e.g., Integer indicates an object of 4 bytes) and its capabilities (e.g., Buttons can be drawn, pressed, and so forth).

Like C++ and Java, Visual Basic .NET divides types into two sets: intrinsic (built-in) types that the language offers and user-defined types that the programmer defines.

Visual Basic .NET also divides the set of types into two other categories: value types and reference types.[2] The principal difference between value and reference types is the manner in which their values are stored in memory. A value type holds its actual value in memory allocated on the stack (or it is allocated as part of a larger reference type object). The address of a reference type variable sits on the stack, but the actual object is stored on the heap.

[2] All the intrinsic types are value types except for Object (discussed in Chapter 5) and String (discussed in Chapter 10). All user-defined types are reference types except for structures (discussed in Chapter 7).

If you have a very large object, putting it on the heap has many advantages. Chapter 5 discusses the various advantages and disadvantages of working with reference types; the current chapter focuses on the intrinsic value types available in Visual Basic .NET.

3.2.1 Working with Built-in Types

The Visual Basic .NET language offers the usual cornucopia of intrinsic (built-in) types one expects in a modern language, each of which maps to an underlying type supported by the .NET Common Language Specification (CLS). Mapping the Visual Basic .NET primitive types to the underlying .NET type ensures that objects created in Visual Basic .NET can be used interchangeably with objects created in any other language compliant with the .NET CLS, such as C#.

Each type has a specific and unchanging size. An Integer, for example, is always 4 bytes because it maps to an Int32 in the .NET CLS. Table 3-1 lists the built-in value types offered by Visual Basic .NET.

Table 3-1. VB.NET built-in value types

Type

Size (in bytes)

.NET Type

Description

Boolean

1

Boolean

True or false.

Byte

1

Byte

Unsigned (values 0-255).

Char

2

Char

Unicode characters.

Date

8

DateTime

1/1/0001 at 0:00:0000 through 12/31/9999 at 23:59:59.

Decimal

16

Decimal

Fixed-precision up to 28 digits and the position of the decimal point. This is typically used in financial calculations. Requires the suffix "m" or "M".

Double

8

Double

Double-precision floating point; holds the values from approximately +/-5.0 * 10-324 to approximate +/-1.8 * 10308 with 15-16 significant figures.

Integer

4

Int32

Signed Integer values between -2,147,483,648 and 2,147,483,647.

Long

8

Int64

Signed integers ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

Short

2

Int16

Signed (short) (values -32,768 to 32,767).

Single

4

Single

Floating point number. Holds the values from approximately +/-1.5 * 10-45 to approximate +/-3.4 * 1038 with 7 significant figures.

String

 

String

A sequence of Unicode characters.

The Stack and the Heap

A stack is a data structure used to store items on a last-in first-out basis (like a stack of dishes at the buffet line in a restaurant). The stack refers to an area of memory supported by the processor, on which the local variables are stored.

In Visual Basic .NET, value types (e.g., integers) are allocated on the stack—an area of memory is set aside for their value, and this area is referred to by the name of the variable.

Reference types (e.g., objects) are allocated on the heap. When an object is allocated on the heap its address is returned, and that address is assigned to a reference.

The garbage collector destroys objects on the stack sometime after the stack frame they are declared within ends. Typically a stack frame is defined by a function. Thus, if you declare a local variable within a function (as explained later in this chapter) the object will be marked for garbage collection after the function ends.

Objects on the heap are garbage collected sometime after the final reference to them is destroyed.

In addition to these primitive types, Visual Basic .NET has two other value types: Enum (considered later in this chapter) and Structure (see Chapter 7). Chapter 6 discusses other subtleties of value types, such as forcing value types to act as reference types through a process known as boxing, and the fact that value types do not "inherit."

3.2.2 Choosing a Built-in Type

Typically you decide which size Integer to use (Integer, Short, or Long) based on the magnitude of the value you want to store. For example, an Integer can only hold the values of approximately negative 2 billion through positive 2 billion, but a Long can hold values from negative 9 quintillion through positive 9 quintillion. So if you have to count, for example, all the people in the world, you would need to use a Long.

Single, Double, and Decimal offer varying degrees of size and precision for rational numbers. For most small fractional numbers, Single is fine.

The Char type represents a Unicode character. If you want to assign a single character literal to a Char variable, and Option Strict is On (as it should be), you must use the literal type character C to force the String to the Char data type. For example, you might write:

Dim myChar As Char
myChar = "X"C

The character literal C following the String "X" forces the conversion to the Char type.

3.2.3 Converting Built-in Types

Objects of one type can be converted into objects of another type. This is called casting.

Casting can be either narrowing or widening. A widening cast is one in which the conversion is to a type that can accommodate every possible value in the existing variable type. For example, an Integer can accommodate every possible value held by a Short. Thus, casting from Short to Integer is a widening conversion.

A narrowing cast is one in which the conversion is to a type that may not be able to accommodate every possible value in the existing variable type. For example, a Short can accommodate only some of the values that an Integer variable might hold. Thus, casting from an Integer to a Short is a narrowing conversion.

In VB.NET, conversions are invoked either implicitly or explicitly. Widening casts are implicit. In an implicit conversion, the compiler makes the conversion with no special action by the developer:

Dim myInteger As Integer = 5
Dim myDouble As Double = myInteger ' implicit cast

Narrowing casts, on the other hand, must be explicit if Option Strict is On:

Dim mySecondInteger As Integer = myDouble ' error! won't compile

With an explicit conversion, the developer must use a special function to signal the cast:

Dim mySecondInteger As Integer = CType(myDouble, Integer) 'ok

The semantics of an explicit conversion are: "Hey! Compiler! I know what I'm doing." This is sometimes called "hitting it with the big hammer" and can be very useful or very painful, depending on whether your thumb is in the way of the nail.

Visual Basic .NET provides a number of explicit casting methods:

CBool( )

Converts any valid string or numeric expression to Boolean. Numeric non-zero values are converted to True, zero is converted to False. The Strings "True" and "False" are converted to True and False, respectively.

CByte( )

Converts numeric expression in range 0 to 255 to Byte; rounds fractional part.

CChar( )

Returns the first character of a String as a Char.

CDate( )

Converts any valid representation of a date or time to the Date type (e.g., "April 15, 2003" is converted to the corresponding Date type).

CDbl( )

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

CDec( )

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

CInt( )

Converts any expression that can be evaluated as a number to an Integer if it is in the range of an Integer; rounds fractional part.

CLng( )

Converts any expression that can be evaluated as a number to a Long if it is in the range of a Long; rounds fractional part.

CObj( )

Converts any expression that can be interpreted as an Object to an Object.

CShort( )

Converts any expression that can be evaluated as a number to a Short if it is in the range of a Short.

CStr( )

If Boolean, converts to the String "True" or "False." If the expression can be interpreted as a date, returns a String expression of the date. For numeric expressions, the returned String represents the number.

CType( )

This is a general purpose conversion function that uses the syntax:

CType(expression, typename)

where expression is an expression or a variable, and typename is the data type to convert to. You can rewrite the following code:

      System.Console.WriteLine( _
          "Freezing point of water: {0}", _
          CInt(Temperatures.FreezingPoint))

to the more generic:

      System.Console.WriteLine( _
          "Freezing point of water: {0}", _
          CType(Temperatures.FreezingPoint, Integer))

  Previous section   Next section
Top