Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Articles
Recherche: 

Recursion
Hilmar Zonneveld, January 1, 2003
Continuing my series of introductory articles, this article presents an introduction of a simple yet powerful programming concept: recursion. Introduction "To understand recursion, you must first understand recursion." "To make yogurt, you need milk and yogurt." If you are not accustomed...
Continuing my series of introductory articles, this article presents an introduction of a simple yet powerful programming concept: recursion.

Introduction

"To understand recursion, you must first understand recursion."

"To make yogurt, you need milk and yogurt."

If you are not accustomed to use recursion, some aspects of it might initially seem as senseless as the above statements (the second one is actually a true statement), or as the story of Münchhausen, who got himself and his horse out of the swamp, by pulling his own hair.

However, there is really nothing mysterious about recursion.

What is it all about?

Well, even if you did only the most basic programming (in Visual FoxPro or otherwise), you probably already know that one function can call another function. (Note: in Visual FoxPro, for practical purposes there is no difference between a function and a procedure. I will use the word "function" in this text.) That is to say, Function_A can call Function_B:

FUNCTION_A
  * Some preliminary code
  Function_B()
  * Some additional code
ENDFUNC

Well, there is nothing that forbids a function to call up itself:

FUNCTION_A
  * Some preliminary code
  Function_A()
  * Some additional code
ENDFUNC

The fact of a function calling itself is called "recursion".

At least three important considerations apply, when you use recursion:

First, all variables have to be declared as local or private. Otherwise, the different instances of the function will overwrite each other's variables. Of course this is proper programming practice anyway, but in the case of a recursive function (that is, one that calls itself), it is a must. With local or private variables, each instance of the function will have its own copy of the variables.

Second, there has to be some condition, implicit or explicit, to end the recursion - otherwise, the program will end up going deeper and deeper (into more and more levels), and never finish.

Third, most programming languages have limits as to how many levels programs can call each other. This limit applies whether one function calls another function, or itself. In Visual FoxPro, this is limited to 128 levels. This can severely limit the scope of recursion. The reason this limit exists is because the executing program has to store information, in a stack, about each executing function - and this stack often has a fixed size.

A primitive example

An example often given for recursion is the factorial function. For instance, the factorial of 5, written as 5!, is defined as 1*2*3*4*5 (multiply all numbers up to the specified number). By the way, 0! is defined as 1.

It is easy to verify, for instance, that 5! = 5 * 4!. But this is, precisely, a recursive definition (the calculation of the factorial of 5 includes the factorial function). The Visual FoxPro code is:

FUNCTION FACTORIAL(number)
  if number = 0
    return 1
  else
    return number * factorial(number-1)
  endif
ENDFUNC

Please note that this is not the most efficient way to solve this particular problem. It is just an illustration of recursion. First, this can easily be solved by a loop - and a program calling itself has much more overhead. Second, we are limited to factorials of small numbers, because of the Visual FoxPro limitation of 128 DO levels.

The loop version, without recursion, might look like this:

FUNCTION FACTORIAL(number)
  local i, factorial
  factorial = 1
  for i = 1 to number
    factorial = factorial * i
  next
  return factorial
ENDFUNC

This version is about as complicated as the first version. However, and although in theory any problem that can be solved with recursion can also be solved without recursion, there are problems that turn out to be very difficult to manage without recursion.

Subfolders

I will now show a more relevant example. It turns out that recursion is ideally suited to do processing in certain cases where there is a natural hierarchy in the data.

One such case is the manipulation of folders that contain subfolders. The definition itself of "folder" is recursive: from the logical standpoint, you can use a definition similar to "A folder is a unit in which you can store files, and other folders". So, using recursion in your programming seems quite natural when you try to process the files - how should I say - "recursively", that is, including all subfolders at different levels.

The following example will list all files with a certain extension on your hard disk. You could easily change it to some other action, for instance, delete *.BAK.

* Sample of recursion with folders: list all files like *.BAK for an entire disk.
local lcExtension, lcStartFolder
lcStartFolder = "c:\"
lcExtension = "BAK"

ProcessFolder(lcStartFolder, lcExtension)

FUNCTION ProcessFolder(pcStartFolder, pcExtension)
  * Process all files in the specified folder, including subfolders
  local i, laFiles(1)
  for i = 1 to adir(laFiles, pcStartFolder + "*.*", "D")
    do case
    case laFiles(i, 1) == "." or laFiles(i, 1) == ".."
      * Ignore entries for current folder and parent folder
    case "D" $ laFiles(i, 5) && it is a directory (folder)
      ProcessFolder(pcStartFolder + laFiles(i, 1) + "\", pcExtension)
    case upper(justext(laFiles(i, 1))) = upper(pcExtension)
      ? pcStartFolder + laFiles(i, 1)
    endcase
  next
ENDFUNC

Note that I stated earlier that there has to be some condition to end the recursion. In this case, the condition comes quite naturally through the structure of the underlying data: the function only calls itself if there are sub-folders. At some point, a folder has no further subfolders to process.

Unlike the factorial, this example is more difficult to process without recursion.

Business logic

You can also use recursion profitably to process all kind of business logic - if there is some kind of hierarchy in your data, you can define and program certain processes recursively. (To actually show the data hierarchically, you might use a treeview control, which allows the user to open and close individual branches. For instance, the treeview control is used in Windows Explorer, to show folders recursively.)

One example of hierarchical data is the accounts used by the accounting department (an account can contain several sub-accounts, and this can continue, through several levels).

Another example is in a manufacturing process: a finished product contains materials. However, a finished product can also contain intermediate products, and these intermediate products then contain the raw materials. This can continue through several levels, where an intermediate may contain other intermediate products.

The advantages of being able to create intermediate products are huge, especially if the intermediate product is used in several places. By creating intermediate products, the data for the intermediate product has to be defined only once. Otherwise, the same listing of raw materials, for what otherwise would be an intermediate product, would have to be repeated in all finished products.

Recursion can be used for several purposes here. For instance, when the user edits the list of materials by product (where either the material, the product, or both, can also be an intermediate product!), you should have validation rules to ensure that a product doesn't contain itself - either directly or indirectly (for instance, "A" contains "B", "B" contains "C", and "C" contains "A"). A product containing itself is an invitation to disaster. This check requires searching (recursively, of course) through the materials contained in the product.

Another use of recursion for the manufacturing process is to produce a list of required raw materials for a certain set of finished products that should be produced. This may be required to purchase the raw materials, or to check whether we have enough of everything in our warehouse. Again, the materials by product have to be processed recursively - this time, multiplying quantities to be produced, by the quantity of the material used in each product.

Some of the details of such a manufacturing process are quite complex, even if you use recursion. Recursion does help a lot, though, to make this sort of problem more manageable.

Summary

As you can see, several problems involving a hierarchy of data, that may look unmanageable at first, in fact turn out to be relatively simple if you use recursion.

Hilmar Zonneveld, Independent Consultant
Hilmar Zonneveld works in programming since 1986, using dBASE, FoxPro and Visual FoxPro. He is available as an independent consultant. He currently works as a programmer at Bata Shoe Organization; also as an instructor at Cisco Networking Academy. You can contact him through the Universal Thread, or, via e-mail, at hilmarz@yahoo.com. Personal Web page (mainly in Spanish): www.geocities.com/hilmarz.
More articles from this author
Hilmar Zonneveld, May 1, 2003
An audit-trail is a record of who did what changes, and when. In Visual FoxPro, this can easily be accomplished through triggers. I hinted at the possibility of doing an audit-trail, in my article on triggers - now, as a reaction to questions in the Universal Thread, I want to present a sample...
Hilmar Zonneveld, December 6, 2001
(The latest update contains minor edits only.) Five easy and fun ways to get yourself into trouble with inheritance. A frequent source of problems in OOP is called "breaking inheritance". This document briefly describes what inheritance is, how it applies to properties and methods, and how it ...
Hilmar Zonneveld, July 1, 2002
Introduction Buffering is a feature in Visual FoxPro that allows us to give the user "undo" and "save" capabilities. In the old FoxPro 2.x days, programmers either didn't provide this capability, or edited memory variables, and copied information between these variables and the table fiel...
Hilmar Zonneveld, October 6, 2005
Due to a recent Windows security fix, users can no longer access a CHM file on a server. The table of contents appears, but the individual pages are replaced by error messages. Access to CHM files in specific folders can be explicitly allowed through special registry settings.
Hilmar Zonneveld, July 20, 2001
(The last update contains minor edits only.) The idea is to have several controls on a form controlled with an array. Thus, you can quickly go through all the controls on the form, managing the array. The sample code included will help you get started quickly. You can easily adapt it to manage...
Hilmar Zonneveld, September 1, 2002
With Automation, you can control all aspects of Excel, Word, or other programs that provide this feature, from Visual FoxPro. In this article, I will concentrate on Excel. Its purpose is to provide a starting point, especially for people new to automation. Introduction With automation, you bas...
Hilmar Zonneveld, March 1, 2003
Introduction One common task in programming is to keep track of what problems are pending. For this purpose, I use a "hierarchical to-do list": a list of items, each of which can have sub-items. All you need is Microsoft Word. Alternatives are available as freeware or shareware, but in t...
Hilmar Zonneveld, October 7, 2005
This is a step-by-step tutorial to show inheritance, specifically in Visual FoxPro forms, as a guidance for people who are not familiar with inheritance in general, or who don’t know how to implement it in Visual FoxPro. The basic idea of inheritance is that all your forms, or several of your for...
Hilmar Zonneveld, May 30, 2004
The code shows how to quickly obtain the greatest common factor, and the least common multiple. Both functions are used when manipulating fractions, among others. Several methods are possible; the method usually taught in school involves prime numbers, but this code will execute much faster (and it ...
Hilmar Zonneveld, November 1, 2006
A standard requirement in a production system, or in systems for cost calculation, is to add up all the raw materials for a number of finished articles, to get the total cost, or simply to purchase the materials. In this article, Hilmar outlines how to do this with multiple levels of intermediate ar...
Hilmar Zonneveld, August 1, 2002
Overview The purpose of this article is to give an overview of normalization. Basically, normalization refers to having an efficient table structure. I will not discuss the famous "first to fifth normal forms" - if you want that information, enough texts exist about it in other places (search sit...
Hilmar Zonneveld, November 8, 2001
The following function will open any document, with its default association (the same application that will be called when you double-click on the file, in Windows Explorer). Use it to open a text-file, a Word or Excel document, an image, etc., with an external application.
Hilmar Zonneveld, May 1, 2002
Introduction This document explains the meaning of primary key, foreign key and candidate index in Visual FoxPro. A discussion of natural and surrogate keys (keys visible, or not visible, to the end-user) is included, including the advantages of each approach, as well as different methods for o...
Hilmar Zonneveld, December 1, 2002
Introduction This article presents an introduction to coding shortcuts in Visual FoxPro - when to use them, and when not to. Notes on coding in general This article is about coding shortcuts; however, I should first emphasize that making the code as small as possible is usually not the number...
Hilmar Zonneveld, July 20, 2001
Rushmore Optimization can help make queries much faster. However, "Full Rushmore Optimization" is not always a desirable goal. "Partial Optimization" is sometimes much faster. It is often believed that to speed things up, you need to have as many indices as possible. This article explains that so...
Hilmar Zonneveld, June 7, 2002
If you need to check elapsed time with seconds() or a datetime value, this function allows you to display the elapsed time in a human-readable format, that is, hours:minutes:seconds, instead of the total number of seconds. Just pass a number of seconds as a parameter.
Hilmar Zonneveld, April 1, 2002
SQL is a standard language used to manipulate databases. Several of the SQL commands are integrated into the Visual FoxPro language. Select This is a very flexible command, used to select data from a table, or from several tables. This command has options to get totals from several record...
Hilmar Zonneveld, August 1, 2003
In this article, I will show several ways to manipulate text-files. Knowledge of these methods is often important to import and export specific formats. Some of the techniques can also be used to work with files of any content; however, this article will concentrate on text-files. When ...
Hilmar Zonneveld, June 1, 2002
The purpose of this article is to show how to use some aspects provided by the Visual FoxPro database engine, to control our data. Indices Perhaps most readers already know indices; anyway, I find it convenient to include a brief summary of the topic, since this is a requisite to understan...
Hilmar Zonneveld, November 1, 2002
A help file can be used either for interactive help, or as an online manual. In this article, I will give an overview over creating help files in the new help format (CHM), for Visual FoxPro 6 and later. This article is introductory and assumes no prior knowledge of the Help Compiler, or of HTML cod...
Hilmar Zonneveld, February 1, 2003
Introduction Any real-world application will sooner or later misbehave. It is important to be able to find those problems. Visual FoxPro's built-in debugger can help a lot to find out why your program doesn't work as you thought it would. Most of the material in this article applies to Visual...
Hilmar Zonneveld, May 1, 2006
This article is an introduction to VisioModeler. This is a free CASE tool, that can help you design your database, in the process sharing the information with the client in a visual, easy-to-understand, format.