- •Using Your Sybex Electronic Book
- •Acknowledgments
- •Contents at a Glance
- •Introduction
- •Who Should Read This Book?
- •How About the Advanced Topics?
- •The Structure of the Book
- •How to Reach the Author
- •The Integrated Development Environment
- •The Start Page
- •Project Types
- •Your First VB Application
- •Making the Application More Robust
- •Making the Application More User-Friendly
- •The IDE Components
- •The IDE Menu
- •The Toolbox Window
- •The Solution Explorer
- •The Properties Window
- •The Output Window
- •The Command Window
- •The Task List Window
- •Environment Options
- •A Few Common Properties
- •A Few Common Events
- •A Few Common Methods
- •Building a Console Application
- •Summary
- •Building a Loan Calculator
- •How the Loan Application Works
- •Designing the User Interface
- •Programming the Loan Application
- •Validating the Data
- •Building a Math Calculator
- •Designing the User Interface
- •Programming the MathCalculator App
- •Adding More Features
- •Exception Handling
- •Taking the LoanCalculator to the Web
- •Working with Multiple Forms
- •Working with Multiple Projects
- •Executable Files
- •Distributing an Application
- •VB.NET at Work: Creating a Windows Installer
- •Finishing the Windows Installer
- •Running the Windows Installer
- •Verifying the Installation
- •Summary
- •Variables
- •Declaring Variables
- •Types of Variables
- •Converting Variable Types
- •User-Defined Data Types
- •Examining Variable Types
- •Why Declare Variables?
- •A Variable’s Scope
- •The Lifetime of a Variable
- •Constants
- •Arrays
- •Declaring Arrays
- •Initializing Arrays
- •Array Limits
- •Multidimensional Arrays
- •Dynamic Arrays
- •Arrays of Arrays
- •Variables as Objects
- •So, What’s an Object?
- •Formatting Numbers
- •Formatting Dates
- •Flow-Control Statements
- •Test Structures
- •Loop Structures
- •Nested Control Structures
- •The Exit Statement
- •Summary
- •Modular Coding
- •Subroutines
- •Functions
- •Arguments
- •Argument-Passing Mechanisms
- •Event-Handler Arguments
- •Passing an Unknown Number of Arguments
- •Named Arguments
- •More Types of Function Return Values
- •Overloading Functions
- •Summary
- •The Appearance of Forms
- •Properties of the Form Control
- •Placing Controls on Forms
- •Setting the TabOrder
- •VB.NET at Work: The Contacts Project
- •Anchoring and Docking
- •Loading and Showing Forms
- •The Startup Form
- •Controlling One Form from within Another
- •Forms vs. Dialog Boxes
- •VB.NET at Work: The MultipleForms Project
- •Designing Menus
- •The Menu Editor
- •Manipulating Menus at Runtime
- •Building Dynamic Forms at Runtime
- •The Form.Controls Collection
- •VB.NET at Work: The DynamicForm Project
- •Creating Event Handlers at Runtime
- •Summary
- •The TextBox Control
- •Basic Properties
- •Text-Manipulation Properties
- •Text-Selection Properties
- •Text-Selection Methods
- •Undoing Edits
- •VB.NET at Work: The TextPad Project
- •Capturing Keystrokes
- •The ListBox, CheckedListBox, and ComboBox Controls
- •Basic Properties
- •The Items Collection
- •VB.NET at Work: The ListDemo Project
- •Searching
- •The ComboBox Control
- •The ScrollBar and TrackBar Controls
- •The ScrollBar Control
- •The TrackBar Control
- •Summary
- •The Common Dialog Controls
- •Using the Common Dialog Controls
- •The Color Dialog Box
- •The Font Dialog Box
- •The Open and Save As Dialog Boxes
- •The Print Dialog Box
- •The RichTextBox Control
- •The RTF Language
- •Methods
- •Advanced Editing Features
- •Cutting and Pasting
- •Searching in a RichTextBox Control
- •Formatting URLs
- •VB.NET at Work: The RTFPad Project
- •Summary
- •What Is a Class?
- •Building the Minimal Class
- •Adding Code to the Minimal Class
- •Property Procedures
- •Customizing Default Members
- •Custom Enumerations
- •Using the SimpleClass in Other Projects
- •Firing Events
- •Shared Properties
- •Parsing a Filename String
- •Reusing the StringTools Class
- •Encapsulation and Abstraction
- •Inheritance
- •Inheriting Existing Classes
- •Polymorphism
- •The Shape Class
- •Object Constructors and Destructors
- •Instance and Shared Methods
- •Who Can Inherit What?
- •Parent Class Keywords
- •Derived Class Keyword
- •Parent Class Member Keywords
- •Derived Class Member Keyword
- •MyBase and MyClass
- •Summary
- •On Designing Windows Controls
- •Enhancing Existing Controls
- •Building the FocusedTextBox Control
- •Building Compound Controls
- •VB.NET at Work: The ColorEdit Control
- •VB.NET at Work: The Label3D Control
- •Raising Events
- •Using the Custom Control in Other Projects
- •VB.NET at Work: The Alarm Control
- •Designing Irregularly Shaped Controls
- •Designing Owner-Drawn Menus
- •Designing Owner-Drawn ListBox Controls
- •Using ActiveX Controls
- •Summary
- •Programming Word
- •Objects That Represent Text
- •The Documents Collection and the Document Object
- •Spell-Checking Documents
- •Programming Excel
- •The Worksheets Collection and the Worksheet Object
- •The Range Object
- •Using Excel as a Math Parser
- •Programming Outlook
- •Retrieving Information
- •Recursive Scanning of the Contacts Folder
- •Summary
- •Advanced Array Topics
- •Sorting Arrays
- •Searching Arrays
- •Other Array Operations
- •Array Limitations
- •The ArrayList Collection
- •Creating an ArrayList
- •Adding and Removing Items
- •The HashTable Collection
- •VB.NET at Work: The WordFrequencies Project
- •The SortedList Class
- •The IEnumerator and IComparer Interfaces
- •Enumerating Collections
- •Custom Sorting
- •Custom Sorting of a SortedList
- •The Serialization Class
- •Serializing Individual Objects
- •Serializing a Collection
- •Deserializing Objects
- •Summary
- •Handling Strings and Characters
- •The Char Class
- •The String Class
- •The StringBuilder Class
- •VB.NET at Work: The StringReversal Project
- •VB.NET at Work: The CountWords Project
- •Handling Dates
- •The DateTime Class
- •The TimeSpan Class
- •VB.NET at Work: Timing Operations
- •Summary
- •Accessing Folders and Files
- •The Directory Class
- •The File Class
- •The DirectoryInfo Class
- •The FileInfo Class
- •The Path Class
- •VB.NET at Work: The CustomExplorer Project
- •Accessing Files
- •The FileStream Object
- •The StreamWriter Object
- •The StreamReader Object
- •Sending Data to a File
- •The BinaryWriter Object
- •The BinaryReader Object
- •VB.NET at Work: The RecordSave Project
- •The FileSystemWatcher Component
- •Properties
- •Events
- •VB.NET at Work: The FileSystemWatcher Project
- •Summary
- •Displaying Images
- •The Image Object
- •Exchanging Images through the Clipboard
- •Drawing with GDI+
- •The Basic Drawing Objects
- •Drawing Shapes
- •Drawing Methods
- •Gradients
- •Coordinate Transformations
- •Specifying Transformations
- •VB.NET at Work: Plotting Functions
- •Bitmaps
- •Specifying Colors
- •Defining Colors
- •Processing Bitmaps
- •Summary
- •The Printing Objects
- •PrintDocument
- •PrintDialog
- •PageSetupDialog
- •PrintPreviewDialog
- •PrintPreviewControl
- •Printer and Page Properties
- •Page Geometry
- •Printing Examples
- •Printing Tabular Data
- •Printing Plain Text
- •Printing Bitmaps
- •Using the PrintPreviewControl
- •Summary
- •Examining the Advanced Controls
- •How Tree Structures Work
- •The ImageList Control
- •The TreeView Control
- •Adding New Items at Design Time
- •Adding New Items at Runtime
- •Assigning Images to Nodes
- •Scanning the TreeView Control
- •The ListView Control
- •The Columns Collection
- •The ListItem Object
- •The Items Collection
- •The SubItems Collection
- •Summary
- •Types of Errors
- •Design-Time Errors
- •Runtime Errors
- •Logic Errors
- •Exceptions and Structured Exception Handling
- •Studying an Exception
- •Getting a Handle on this Exception
- •Finally (!)
- •Customizing Exception Handling
- •Throwing Your Own Exceptions
- •Debugging
- •Breakpoints
- •Stepping Through
- •The Local and Watch Windows
- •Summary
- •Basic Concepts
- •Recursion in Real Life
- •A Simple Example
- •Recursion by Mistake
- •Scanning Folders Recursively
- •Describing a Recursive Procedure
- •Translating the Description to Code
- •The Stack Mechanism
- •Stack Defined
- •Recursive Programming and the Stack
- •Passing Arguments through the Stack
- •Special Issues in Recursive Programming
- •Knowing When to Use Recursive Programming
- •Summary
- •MDI Applications: The Basics
- •Building an MDI Application
- •Built-In Capabilities of MDI Applications
- •Accessing Child Forms
- •Ending an MDI Application
- •A Scrollable PictureBox
- •Summary
- •What Is a Database?
- •Relational Databases
- •Exploring the Northwind Database
- •Exploring the Pubs Database
- •Understanding Relations
- •The Server Explorer
- •Working with Tables
- •Relationships, Indices, and Constraints
- •Structured Query Language
- •Executing SQL Statements
- •Selection Queries
- •Calculated Fields
- •SQL Joins
- •Action Queries
- •The Query Builder
- •The Query Builder Interface
- •SQL at Work: Calculating Sums
- •SQL at Work: Counting Rows
- •Limiting the Selection
- •Parameterized Queries
- •Calculated Columns
- •Specifying Left, Right, and Inner Joins
- •Stored Procedures
- •Summary
- •How About XML?
- •Creating a DataSet
- •The DataGrid Control
- •Data Binding
- •VB.NET at Work: The ViewEditCustomers Project
- •Binding Complex Controls
- •Programming the DataAdapter Object
- •The Command Objects
- •The Command and DataReader Objects
- •VB.NET at Work: The DataReader Project
- •VB.NET at Work: The StoredProcedure Project
- •Summary
- •The Structure of a DataSet
- •Navigating the Tables of a DataSet
- •Updating DataSets
- •The DataForm Wizard
- •Handling Identity Fields
- •Transactions
- •Performing Update Operations
- •Updating Tables Manually
- •Building and Using Custom DataSets
- •Summary
- •An HTML Primer
- •HTML Code Elements
- •Server-Client Interaction
- •The Structure of HTML Documents
- •URLs and Hyperlinks
- •The Basic HTML Tags
- •Inserting Graphics
- •Tables
- •Forms and Controls
- •Processing Requests on the Server
- •Building a Web Application
- •Interacting with a Web Application
- •Maintaining State
- •The Web Controls
- •The ASP.NET Objects
- •The Page Object
- •The Response Object
- •The Request Object
- •The Server Object
- •Using Cookies
- •Handling Multiple Forms in Web Applications
- •Summary
- •The Data-Bound Web Controls
- •Simple Data Binding
- •Binding to DataSets
- •Is It a Grid, or a Table?
- •Getting Orders on the Web
- •The Forms of the ProductSearch Application
- •Paging Large DataSets
- •Customizing the Appearance of the DataGrid Control
- •Programming the Select Button
- •Summary
- •How to Serve the Web
- •Building a Web Service
- •Consuming the Web Service
- •Maintaining State in Web Services
- •A Data-Driven Web Service
- •Consuming the Products Web Service in VB
- •Summary
812 Chapter 18 RECURSIVE PROGRAMMING
Basic Concepts
Recursive programming is used for implementing algorithms, or mathematical definitions, that are described recursively, that is, in terms of themselves. A recursive definition is implemented by a procedure that calls itself; thus, it is called a recursive procedure.
Code that calls functions and subroutines to accomplish a task, such as the following segment, is quite normal:
Function MyPayments() { other statements }
CarPayment = CalculateCarPayment(Interest, Duration) HomePayment = CalculateHomePayment(Interest, Duration) MonthlyPayments = CarPayment + HomePayment
{ more statements } End Function
In the preceding code, the MyPayments() function calls two functions to calculate the monthly payments for a car and home loan. There’s nothing puzzling about this piece of code because it’s linear. Here’s what it does:
1.The MyPayments() function suspends execution each time it calls a function (the CalculateCarPayment() and CalculateHomePayment() functions).
2.It waits for each function to complete its task and return a value.
3.It then resumes execution.
But what if a function calls itself? Examine the following code:
Function DoSomething(n As Integer) As Integer
{other statements } value = value - 1
If value = 0 Then Exit Function newValue = DoSomething(value)
{more statements }
End Function
If you didn’t know better, you’d think that this program would never end. Every time the DoSomething() function is called, it gets into a loop by calling itself again and again, and it never exits. In fact, this is a clear danger with recursion. It’s not only possible but also quite easy for a recursive function to get into an endless loop. A recursive function must exit explicitly. In other words, you must tell a recursive function when to stop calling itself and exit. The condition that causes the DoSomething() function to end is met when value becomes zero. If the initial value of this variable is negative, the function will never end, because value will never become zero. This is a typical logical error you must catch from within your code.
Apart from this technicality, you can draw a few useful conclusions from this example. A function performs a well-defined task. When a function calls itself, it has to interrupt the current task to complete another, quite similar task. The DoSomething() function can’t complete its task (whatever this is) unless it performs an identical calculation, which it does by calling itself.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
BASIC CONCEPTS 813
Recursion in Real Life
Do you ever run into recursive processes in your daily tasks? Suppose you’re viewing a World Wide Web page that describes a hot new topic. The page contains a term you don’t understand, and the term is a hyperlink. When you click the hyperlink, another page that defines the term is displayed. This definition contains another term you don’t understand. The new term is also a hyperlink, so you click it and a page containing its definition is displayed. Once you understand this definition, you click the Back button to go back to the previous page where you re-read the term, knowing its definition. You then go back to the original page.
The task at hand involves understanding a topic, a description, and a definition. Every time you run into an unfamiliar term, you interrupt the current task to accomplish another identical task, such as learning another term.
The process of looking up a definition in a dictionary is similar, and it epitomizes recursion. For example, if the definition of an ASP page is “ASP pages are Web pages that contain Web controls,” you’d probably have to look up the definition of Web controls. Once you understand what Web controls are, you can go back and understand the other definitions. Let’s say that Web controls are defined as “elements used to build ASP Web pages.” This is a sticky situation, indeed. At this point, you’d either have to interrupt your search or look up its definition elsewhere. Going back and forth between these two definitions won’t take you anywhere. This is the endless loop mentioned earlier.
Because endless loops can arise easily in recursive programming, you must be sure that your code contains conditions that will cause the recursive procedure to stop calling itself. In the example of the DoSomething() function, this condition is as follows:
If value = 0 Then Exit Function
The code reduces the value of the variable value by increments of 1 until it eventually reaches 0, at which point the sequence of recursive calls ends (provided the initial value of the variable is positive, because if you start with a negative value you’ll never reach zero). Without such a condition, the recursive function would call itself indefinitely. Once the DoSomething() function ends, the suspended instances of the same function resume their execution and terminate.
When you interrupt a task to perform another similar task, you’re performing some type of recursion. Each new task in the process involves a different definition, but the goal is to gather all the information you need to complete the initial task. Now, let’s look at a few practical examples and see these concepts in action. The first example is a trivial one, but you’ll be able to follow the thread of recursive calls and understand how recursion works. In the following sections, we’ll build more difficult, and practical, recursive procedures.
A Simple Example
I’ll demonstrate the principles of recursive programming with a simple example: the calculation of the factorial of a number. The factorial of a number, denoted with an exclamation mark, is described recursively as follows:
n! = n * (n-1)!
The factorial of n (n!, read as “n factorial”) is the number n multiplied by the factorial of (n – 1), which in turn is (n – 1) multiplied by the factorial of (n – 2) and so on, until we reach 0!, which is 1 by definition.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
814 Chapter 18 RECURSIVE PROGRAMMING
Here’s the process of calculating the factorial of 4:
4! = 4 * 3!
=4 * 3 * 2!
=4 * 3 * 2 * 1!
=4 * 3 * 2 * 1 * 0!
=4 * 3 * 2 * 1 * 1
=24
For the mathematically inclined, the factorial of the number n is defined as follows:
n! |
= |
n * (n-1)! |
if |
n |
is |
greater than zero |
n! |
= |
1 |
if |
n |
is |
zero |
The factorial is described in terms of itself, and it’s a prime candidate for recursive implementation. The Factorial application, shown in Figure 18.1, lets you specify the number whose factorial you want to calculate in the box on the left and displays the result in the box on the right. To start the calculations, click the Factorial button.
Figure 18.1
The Factorial application
Here’s the Factorial() function that implements the previous definition:
Function Factorial(n As Integer) As Double
If n = 0 Then
Factorial = 1
Else
Factorial = n * Factorial(n - 1)
End If
End Function
The recursive definition of the factorial of an integer is implemented in a single line:
Factorial = n * Factorial(n-1)
As long as the argument of the function isn’t zero, the function returns the product of its argument times the factorial of its argument minus 1. With each successive call of the Factorial() function, the initial number decreases by an increment of 1, and eventually n becomes 0 and the sequence of recursive calls ends. Each time the Factorial() function calls itself, the calling function is suspended temporarily. When the called function terminates, the most recently suspended function resumes execution. To calculate the factorial of 10, you’d call the Factorial() function with the argument 10, as follows:
MsgBox(“The factorial of 10 “ & Factorial(10))
The execution of the Factorial(10) function is interrupted when it calls Factorial(9). This function is also interrupted when Factorial(9) calls Factorial(8), and so on. By the time Factorial(0) is called, 10 instances of the function have been suspended and made to wait for the function they
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
BASIC CONCEPTS 815
called to finish. When that happens, they resume execution. The first instance to resume its execution is the Factorial(1), then the Factorial(2), and so on.
Let’s see how this happens by adding a couple of lines to the Factorial() function. Open the Factorial application and add a few statements that print the function’s status in the Output window, as shown in Listing 18.1.
Listing 18.1: The Factorial() Recursive Function
Function Factorial(n As Integer) As Double Console.WriteLine(“Starting the calculation of “ n & “ factorial”) If n = 0 Then
Factorial = 1 Else
Console.WriteLine(“Calling Factorial(” & n – 1 & ”)”) Factorial = Factorial(n - 1) * n
End If
Console.WriteLine(“Done calculating “ & n & “ factorial”) End Function
Watching the Algorithm
You can watch the execution of the algorithm by inserting a few statements that display the progress on the Output window (the WriteLine statements in Listing 18.1). The first WriteLine statement tells us that a new instance of the function has been activated and gives the number whose factorial it’s about to calculate. The second WriteLine statement tells us that the active function is about to call another instance of itself and shows which argument it will supply to the function it’s calling. The last WriteLine statement informs us that the factorial function is done. Here’s what you’ll see in the Output window if you call the Factorial() function with the argument 4:
Starting the calculation of 4 factorial
Calling Factorial(3)
Starting the calculation of 3 factorial
Calling Factorial(2)
Starting the calculation of 2 factorial
Calling Factorial(1)
Starting the calculation of 1 factorial
Calling Factorial(0)
Starting the calculation of 0 factorial
Done calculating 0 factorial
Done calculating 1 factorial
Done calculating 2 factorial
Done calculating 3 factorial
Done calculating 4 factorial
This list of messages is lengthy, but it’s worth examining for the sequence of events. The first time the function is called, it attempts to calculate the factorial of 4. It can’t complete its operation
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
816 Chapter 18 RECURSIVE PROGRAMMING
and calls Factorial(3) to calculate the factorial of 3, which is needed to calculate the factorial of 4. The first instance of the Factorial() function is suspended until Factorial(3) returns its result.
Similarly, Factorial(3) doesn’t complete its calculations because it must call Factorial(2). So far, there are two suspended instances of the Factorial() function. In turn, Factorial(2) calls Factorial(1), and Factorial(1) calls Factorial(0). Now, there are four suspended instances of the Factorial() function, all waiting for an intermediate result before they can continue with their calculations. Figure 18.2 shows this process.
Figure 18.2
You can watch the progress of the calculation of a factorial in the Output window.
When Factorial(0) completes its execution, it prints the following message and returns a result:
Done calculating 0 factorial
This result is passed to the most recently interrupted function, which is Factorial(1). This function can now resume operation, complete the calculation of 1! (1 × 1), and then print another message indicating that it finished its calculations.
As each suspended function resumes operation, it passes a result to the function from which it was called, until the very first instance of the Factorial() function finishes the calculation of the factorial of 4. Figure 18.3 shows this process. (In the figure, factorial is abbreviated as fact.) The arrows pointing to the right show the direction of recursive calls, and the ones pointing to the left show the propagation of the result.
Figure 18.3
Recursive calculation of the factorial of 4
What Happens When a Function Calls Itself
If you’re completely unfamiliar with recursive programming, you’re probably uncomfortable with the idea of a function calling itself. Let’s take a closer look at what happens when a function calls itself.
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |
BASIC CONCEPTS 817
As far as the computer is concerned, it doesn’t make any difference whether a function calls itself or another function. When a function calls another function, the calling function suspends execution and waits for the called function to complete its task. The calling function then resumes (usually by taking into account any result returned by the function it called). A recursive function simply calls itself instead of another one.
Let’s look at what happens when the factorial in the previous function is implemented with the following line in which Factorial1() is identical to Factorial():
Factorial = n * Factorial1(n-1)
When the Factorial() function calls Factorial1(), its execution is suspended until Factorial1() returns its result. A new function is loaded into the memory and executed. If the Factorial() function is called with 3, the Factorial1() function calculates the factorial of 2.
Similarly, the code of the Factorial1() function is
Factorial1 = n * Factorial2(n-1)
This time, the function Factorial2() is called to calculate the factorial of 1. The function Factorial2() in turn calls Factorial3(), which calculates the factorial of 0. The Factorial3() function completes its calculations and returns the result 1. This is in turn multiplied by 1 to produce the factorial of 1. This result is returned to the function Factorial1(), which completes the calculation of the factorial of 2 (which is 2 × 1). The value is returned to the Factorial() function, which now completes the calculation of 3 (3 × 2, or 6). As you understand, we can’t write dozens of identical functions; accounting for this is what recursive functions do for your applications.
Recursive Calls and the Operating System
You can think of a recursive function calling itself as the operating system supplying another identical function with a different name; it’s more or less what happens. Each time your program calls a function, the operating system does the following:
1.Saves the status of the active function
2.Loads the new function in memory
3.Starts executing the new function
If the function is recursive—in other words, if the new function is the same as the one currently being executed—nothing changes. The operating system saves the status of the active function somewhere and starts executing it as if it was another function. Of course, there’s no reason to load the code in memory again because the function is already there. The new instance of the function consists of a new set of local variables. The same code will act on different variables and produce a different result. When the newly called function finishes, the operating system reloads the function it interrupted
in memory and continues its execution. I mentioned that the operating system stores the status of a function every time it must interrupt it to load another function in memory. The status information includes the values of its variables and the location where execution was interrupted. In effect, after the operating system loads the status of the interrupted function, the function continues execution as if it was never interrupted. We’ll return to the topic of storing status information later on in the section “The Stack Mechanism.”
Copyright ©2002 SYBEX, Inc., Alameda, CA |
www.sybex.com |