Overview of the Visual FoxPro Object Model


Savannah Brentnall
Visual Training Group

Introduction

The terminology associated with object orientation may seem confusing at first. Why do we need terms like class and method when function has always done the job perfectly well in the past? The reason is that the job has changed somewhat. Instead of calling a function to perform a task on some data, we ask the data to perform that task on itself, using whatever method that class of data normally uses.

Class

A class is a template that describes all the properties (instance variables) and behaviors (methods) of a particular type of data. (We know, you’ve heard that definition before. But it’s really the best way to describe a class.) For example, a class called Box would probably contain information on the coordinates of a box and the characters used for its outline, and would contain code for all box operations, such as Display, Move, Resize, and so on. For example:
DEFINE CLASS Box AS Custom
 nTop  = 0
 nLeft  = 0
 nBottom = 0
 nRight = 0
 >cOutlineChar = “/-\|/-\|”
 PROCEDURE Display
 @ this.nTop, this.nLeft, this.nBottom, this.nRight BOX cOutlineChar
 ENDPROC
ENDDEFINE
You may find it helpful to think of a class as a “cookie cutter” that manufactures objects. This is shown in Figure 1.

Figure 1. A class is a “cookie cutter”

Remember, a class is just a template. It doesn’t actually perform these operations; it merely describes how they should be performed. To actually store data and act upon it, you need an object.

Object

An object is an instance of a class. That’s why the process of creating an object is known as instantiation: we’re creating an instance of a class. For example, Box is a class, but you need to create a Box object in order to use the methods defined in that class.

The following code creates a Box object (an instance of the Box class) from the class shown in the previous section:

oBox = CreateObject( “Box”, 10, 10, 20, 35 )
This code asks the Box class to create a new instance of itself using the coordinates 10,10 and 20,35 as the top left and bottom right corners of the box. A reference to this new object is then assigned to the memory variable oBox. It’s important to note that oBox is just a regular memory variable, and can be local, public or private. The only thing special about it is that the data it contains isn’t of type character, numeric, etc., but is of type “object reference.”

Constructor

Whenever an object is created from a class, a method called a constructor is executed. This simply sets the initial values of the instance variables. FoxPro allows you to specify a method called Init to use as a constructor. This method can take any number of parameters, which are passed using the following syntax:

oBox = CreateObject( “Box”, 10, 10, 20, 35 )
In the above example, the parameters are marked in bold italics. Here’s a simple constructor for the Box class:
PROCEDURE Init()
 this.nTop     = 0
 this.nLeft    = 0
 this.nBottom   = 0
 this.nRight    = 0
 this.cOutlineChar = “|/-\|/-\”
 >ENDPROC
You may notice that these assignments look the same as the ones we previously placed in the class definition for the Box class. In fact, they are. If the initialization process is as simple as setting initial values of some properties, you can place the initialization code immediately following the DEFINE CLASS line. However, you may sometimes want to perform more complex processing in the constructor. Let’s develop the Box constructor a little further, and enable it to take parameters:
PROCEDURE Init( top, left, bottom, right )
 this.nTop     = IIf( Empty(top),  0, top )
 this.nLeft    = IIf( Empty(left),  0, left )
 this.nBottom   = IIf( Empty(bottom), 0, bottom )
 this.nRight    = IIf( Empty(right), 0, right )
 this.cOutlineChar = “|/-\|/-\”
 ENDPROC
This constructor accepts the coordinates of the box as optional parameters. If none are passed, the coordinates default to zero. The passing of parameters to a constructor is entirely optional. In this case, it makes sense, since it is impossible to have a box that doesn’t have coordinates.

Some languages use both class constructors and class initializers. The constructor is used to actually create the object, and performs tasks like reserving memory and storage space. The initializer initializes the object’s instance variables, as we’re doing in the above example. Since FoxPro handles memory management for us, we roll the class constructor and the initializer into one method, called Init.

Property (Instance Variable)

A property, known in object orientation terms as an instance variable. is simply a variable used to store data in an object. The name instance variable is derived from the fact that an object is an instance of a class, and the object’s data is stored in a variable.

A property is accessed by sending a message to the object. The following example uses a Box object’s cOutlineChar property:

oBox = CreateObject( “Box”, 10, 10, 20, 35 )
* Ask the Box object for the value of its cOutlineChar property
? oBox.cOutlineChar      && Displays “|/-\|/-\”
* Assign a new value to the cOutlineChar property
? oBox.cOutlineChar = “|/=\|/=\”
? oBox.cOutlineChar     && Displays “|/=\|/=\”
Method

A method is a piece of code that performs an action with an object’s data. It is declared as part of the class definition, and is invoked by sending a message to an object. Within a class, a method of that class is invoked by sending a message to this (see This, later in this paper). For example:

oBox = CreateObject( “Box”, 10, 10, 20, 35 )
* Send a Display message to the oBox object, asking it
* to invoke the Display method in the Box class
=oBox.Display()
Message

In order to invoke a method or query an object’s data, a message must be sent to the object. A message usually consists of the name of the object, followed by the name of a method that the object knows how to execute, followed by any parameters. For example, the message to lock a file in a database might look like this:

Figure 2. The structure of a message

The above diagram is described as “sending a Display message to oBox.” The effect of this message is to invoke the Display method for the oBox object, and pass the .T. as a parameter.

Note this example assumes that the Display method shown earlier has been amended to accept a logical parameter.

Let’s look at a code example.

cOutlineChar = “|/-\|/-\|”
cText    = “Text in a box”
=DispBox( 10, 10, 22, 78, cText, cOutlineChar, .T. )
In the above example, a traditional function is used to display a piece of text centered in a box. This function would probably be stored in a function library. Compare that with the example below, where a Display message is sent to a TextBox object:
oTextBox = CreateObject( “TextBox”, 10, 10, 22, 78, “Text in a box” )
oTextBox.cOutlineChar = “|/-\|/-\|”
oTextBox.lCenter   = .T.
=oTextBox.Display()
The "New" Message

Most object-oriented languages send a New message to a class in order to create an object. This automatically invokes the constructor method for an object of that class. As we’ve already seen, FoxPro uses the CreateObject() function to create objects. When you look at magazines that specialize in object orientation, lines such as this:

oBox := Box.New( 10, 10, 20, 35 )
are equivalent to FoxPro’s
oBox = CreateObject( “Box”, 10, 10, 20, 35 )
Self/This

So far, all the examples I’ve used send messages to objects using the following syntax:

object.message
However, if you need to access an object from within one of its own methods, a slightly different syntax is used:
this.message
This is shorthand for “send the message on the right to myself.” “Myself,” in this context, is the object to which a message was sent in order to execute the current method. Most object-oriented languages, such as Smalltalk, use “self” instead of “this.” The Microsoft languages, however, use “this.”

Let’s look at another example:

* Box.prg  * String.prg
DEFINE CLASS Box AS Custom  DEFINE CLASS String AS Custom
 cOutline = “/-\|/-\|” 
PROCEDURE Init( top, left, ;  PROCEDURE Init( contents)
 bottom, right)  <constructor code>
 <constructor code> ENDPROC 
ENDPROC 

PROCEDURE Display()  METHOD Display( nRow, nCol )
 @ this.nTop, this.nLeft,;   this.nBottom, this.nRight ;   @ nRow,nCol SAY this.cContents
 BOX this.cOutline   ENDPROC
ENDPROC

ENDDEFINE   ENDDEFINE

  oBox  = CreateObject( “Box”, 10, 10, 20, 35 ) 
  oString = CreateObject( “String”, “Visual Training Group” ) 
  * Inside this Display method, this = oBox 
  =oBox.Display() 
  * Inside this Display method, this = oString 
  =oString.Display( 22,10 ) 
Notice how the same message (Display) is being sent to objects of two different classes, with different results. This capability is called polymorphism, and will be discussed later.

Inheritance

So far, you may be wondering why there’s so much fuss about object-oriented programming. Well, inheritance is one of the capabilities that makes object orientation so popular.

Imagine that you have a Box routine similar to the class listed above. It may even have been written by another programmer, or be part of the company code library. Either way, it works and you don’t want to mess with it. Unfortunately, you need a box routine that asks the user to type “Y” or “N” after displaying its contents.

In a traditional application, you’d have to do one of two things:

  1. Modify the Box routine to accept a logical parameter indicating whether or not to accept input from the user.

  2. Create a new function that calls the Box routine, then displays the call for input underneath.
There are problems with both these approaches. The first option means modifying an existing piece of code that is known to be problem-free, and may be used in its current state by many other people. The second option is a bit of a kludge—it forces you to lengthen the box by one line or more in order to display the request for input. It also relies on the fact that you have the source code to the original routine, which is not always the case.

In an object-oriented language, the answer is simple: create a new class, YesNoBox, that inherits all the properties and methods of the original Box class. YesNoBox can add properties and methods of its own, and can modify and redefine those inherited from Box. For example:

DEFINE CLASS YesNoBox AS Box
FUNCTION Display
	LOCAL cAnswer = " "
	
	* Call Display method in Box class. This just displays the box
	=Box::Display()
	* Get the user's response
	@ this.nBottom-1, this.nLeft + 2 GET cAnswer PICTURE "Y"
	READ
RETURN ( cAnswer == "Y" )
Now, I can display a Yes/No box using the following code:
oBox      = CreateObject( "YesNoBox", 10, 12, 20, 45 )
oBox.cContents = "Cannot open Customer file. Continue (Y/N)?"
lContinue   = oBox.Display()
In this example, the Box class is known as the superclass or parent class. The YesNoBox class is known as the subclass. The line “=Box::Display()” uses FoxPro’s scope resolution operator (::) to send a message directly to the Box class. The reason for this is that the Box class contains a perfectly good routine to display a box on the screen. Even though we’re going to ask the user for input, we need to display the box first. Instead of rewriting all that code, why not just call the Display method in the Box class?

Multiple Inheritance

So far, we’ve only talked about subclasses inheriting from a single superclass. However, some products allow a subclass to inherit from multiple superclasses. This is known as multiple inheritance.

Use of multiple inheritance adds a number of complex problems to system design. The first problem is one of name clashing. If you’re inheriting from two classes that both contain a method with the same name, which ne do you execute?

In general, many people use multiple inheritance to work around earlier design problems. It is usually possible to avoid multiple inheritance by use of delegation, which is explained later.

The use of multiple inheritance is still the subject of much debate in object orientation circles. Many people believe that it adds an unnecessary layer of complexity to a system, without a corresponding gain in functionality. Since I tend to fall in this camp (!), we’ll use single inheritance in all our examples.

Hierarchies

Most people envision classes and subclasses as a kind of tree diagram. In fact, the organization of the classes in a system is usually referred to as a class tree or class hierarchy. This hierarchy can grow quite large as a system develops, and several tools have been developed to make it easier to represent this hierarchy as a diagram. In addition, many object-oriented languages, such as Smalltalk, incorporate a graphical browser, which shows the classes in a tree format.

Finding Methods and Variables in a Hierarchy

When an object receives a message, it looks in its class definition for a corresponding method. If no method is found, the request is passed “up the tree” to its superclass (see Figure 3). This process continues until the method is found. If the object gets to the top of the class hierarchy and still hasn’t found a matching method, an error is displayed. The same process is conducted when an object tries to locate one of its variables.

Figure 3. Searching for the hide method

Since it can take time for the entire hierarchy to be scanned, object-oriented systems can be slower than their procedural counterparts. However, this is becoming less and less of an issue as object-oriented languages evolve and become faster.

Polymorphism

Polymorphism is the ability to send the same message (such as Display) to objects of different classes, and have each object respond in its own way. Although this can be mimicked without object orientation, the code tends to become unmanageable.

Consider the following example:

cString = "This is a string"
=Display( cString, 10, 10 )
nNumber = 135
=Display( nNumber, 10, 10 )
dDate  = CToD( "05/05/93" )
=Display( dDate, 10, 10 )

PROCEDURE Display( xItem, nRow, nCol )
	DO CASE
	CASE Type( "xItem" ) = "C"
		@ nRow,nCol SAY xItem
	CASE Type( "xItem" ) = "N"
		@ nRow,nCol SAY Str( xItem )
	CASE Type( "xItem" ) = "D"
		@ nRow,nCol SAY DToC( xItem )
	ENDCASE
RETURN
It’s convenient to be able to use the same function name for displaying different types of data, but FoxPro will report a naming conflict if you do that. The only solution, without object orientation, is to create a single function that contains a CASE statement to handle every possible data type. As you can imagine, that quickly becomes cumbersome.

When you’re using an object-oriented language, each class can have its own Display method. You no longer have to concern yourself with naming conflicts. This has the added advantage of enabling you to create classes that are completely self-contained, or encapsulated. In an object-oriented language, the example above would look like this:

DEFINE CLASS String AS Custom
	
PROCEDURE Display
	
ENDPROC
ENDDEFINE

DEFINE CLASS Number AS Custom
	
PROCEDURE Display
	
ENDPROC

DEFINE CLASS Date AS Custom
	
PROCEDURE Display
	
ENDPROC
ENDDEFINE

* Somewhere in your code
=oObject.Display()
Encapsulation

Encapsulation is the building of self-contained, “black-box” code. In traditional structured programming, it means creating functions that don’t rely on the values of variables defined in higher-level routines, but explicitly passing to those functions all the data they need to in order to operate.

In an object-oriented language, an encapsulated class is one that contains all the instance variables and methods it needs in order to complete its task. It should contain its own Display, Edit and Save methods, for example, instead of calling routines from a common library.

An encapsulated class is also one that hides its implementation from “outsiders.” For example:

* Wrong:
oDbf   = CreateObject( "Database", "Customer )
nOldArea = Select()
=oDbf.Browse()
SELECT ("nOldArea")

* Right:
oDbf   = CreateObject( "Database", "Customer )
=oDbf.Browse()
* In Database class:
PROCEDURE Browse()
	LOCAL nOldArea = Select()
	.
	. 
	.
	SELECT ("nOldArea")
ENDPROC
In the first example, the calling routine is forced to save the current workarea before sending a Browse message to the database object. The is incorrect—a well-designed Database class should save the state of the environment on entry and restore it upon returning. As the user of the Database class, you shouldn’t have to concern yourself with implementation details such as whether or not the Browse method saves the current workarea first.

Encapsulation is similar to the principal of information hiding that was a cornerstone of traditional structured programming. Object-oriented languages simply enforce this principal rather than leaving it up to individual programmers to implement.

Encapsulation not only protects an object’s data from corruption by outside sources, but it also protects other objects from relying on an object’s internal structure. If a Customer class is properly encapsulated, for example, we can change the way it calculates its outstanding invoice amount by changing just one piece of code: the Customer class itself. Other objects continue to ask a customer object to calculate the amount as usual—they don’t care that the internal process has changed.

Composite (Container) Objects

Some objects have characteristics that are too complex to be stored as simple numbers or text strings. For example, a Customer class has a database as one of its characteristics, but that database has characteristics and functions of its own. In an object-oriented language, this would be represented by a composite object (known in FoxPro as a container object).

Figure 4. A composite object

A composite object is one that contains one or more other objects. This means that we can create a Database class that describes the characteristics and behaviors of a database, and include an object of that class inside our Customer class (see Figure 4).

Let’s look at a source code example. The following code shows a piece of the class definition for a basic Customer class.

DEFINE CLASS Customer AS Custom
	lNew    = ""					&& Is this a new customer?
	cName    = ""					&& Name of customer
	cMail1   = ""					&& Mailing address
	cMail2   = ""
	cMail3   = ""
	cMail4   = ""
	cMailState = ""
	cMailZip  = ""
	cOther1   = ""					&& Other address
	cOther2   = ""
	cOther3   = ""
	cOther4   = ""
	cOtherState = ""
	cOtherZip  = ""
	cContact  = ""					&& Contact name
	cTitle   = ""					&& Contact title
	cPhone   = ""					&& Phone number
	c800Phone  = ""					&& 800 number
	cFax    = ""					&& Fax number
	
	ADD OBJECT oDbf AS Database		&& Database object for this class
The last line shows the definition of a property called oDbf. This is a database object used for storing the customer information. Since the Customer class may be used in many different applications, it makes sense to incorporate the database object as part of the class definition.

To set up this database object, we change the last line as follows:

ADD OBJECT oDbf AS Database;
 WITH cName = “Customer”, lNetwork = .T.

You can initialize as many properties as you want in this way: just separate them with commas.

Since the Customer object contains a Database object, we call it a composite object, created from a composite class.

Delegation

Many composite classes contain two-line methods that simply pass a message along to the object contained in one of their properties. For example, the CloseDbf method for the Customer class shown above might look like this:

PROCEDURE CloseDbf()
 this.oDbf.Close()
ENDPROC
This is known as delegation or message forwarding, since we’re delegating responsibility for the task to another class, and forwarding the message to another object. It’s useful because it means that other programmers only need to communicate with the Customer class. They don’t care that the Customer class uses a Database object to perform some of its tasks, since this fact is hidden from them. This in turn allows us to modify the implementation of the Customer class—maybe by removing the Database object, for example—without breaking anyone else’s code.

Scope and Visibility

With the development of modular programming languages such as C and Pascal, the concept of variable scoping was introduced. This provided a much better way to control access to data in the program. Data could be restricted to a single subroutine (or procedure), or could be made available to the entire program. The ability of a procedure to control its own data provided a form of protection against outside invaders. Further development of scoping concepts enabled the nesting and restriction of procedures in the same fashion.

Scoping of Variables

There are several types of scoping options for data: public, private, and local. The following table gives an overview of the different scopes available in FoxPro. In the next few sections, we’ll look at each one in turn.

Scopting Option Visibility Lifetime
PUBLIC Entire application Entire application
PRIVATE Creator routine and its subroutines Creator routine and its subroutines
LOCAL Creator routine Creator routine and its subroutines

Public Scoping

The oldest and worst form of scoping is global scoping, implemented in FoxPro in the form of public variables. Data that has a global scope is reachable by all parts of the software system. This is generally not wise, since any routine may access or modify the data at any time. Global data may result in the weakening of the software system, since the impact of changes may become harder to predict. In general, only the parts of the system which actually use the data should have access to it.

Private Scoping

Private variables allow a limited form of control over access to variables. Data that is stored in a private variable may be modified by the current procedure, or any of the procedures which it calls. This provides a better form of scoping than global scoping; however, it still leaves a great deal to be desired. Consider the following code sample:

PROCEDURE Proc1()
	PRIVATE i
	FOR i = 1 TO 100
		? i
		=Proc2()
	NEXT
RETURN

PROCEDURE Proc2()
	FOR i = 1 TO 10
		? i
	NEXT
RETURN
This code will fall into an infinite loop, since the second procedure, Proc2(), will always set the value of i to 10. The calling routine, Proc1(), will never terminate the FOR loop. This is probably not what the programmer intended when s/he wrote this piece of code.

Local Scoping

Local scoping, which is new in Visual FoxPro, makes it possible to prevent the kind of programming error shown above. Locally scoped variables can only be accessed by the function or procedure in which they are defined. In order for the value to be accessed by a called procedure, it must be passed in as a parameter. In the above example, if i is declared in Proc1() as a local variable, it is only visible in Proc1(). In order for Proc2() to see i, Proc1() must pass i to Proc2(), like this:

=Proc2(i)
Note The examples shown above use the “function-calling” syntax. This syntax can be used with both functions and procedures. I prefer to use this syntax because it passes parameters by value as a default, whereas the traditional “DO xxx” syntax defaults to passing parameters by reference.

Scoping of Properties and Methods

Scoping is not limited to variables and functions. Most object-oriented languages also allow scoping control over the instance variables and methods of the object. Some languages even allow for scoping of classes. First, let’s have a look at the available scopes:

Visibility and lifetime

EXPORTED Entire application

PROTECTED Creator class and its subclasses Scoping of Properties

As we have seen, a class acts as a cookie-cutter for objects. It defines what kinds of properties an object will have, and what actions may be performed on it. These properties can be defined with various scoping restrictions, which can aid in the design of a robust class structure. Most object-oriented languages allow for two basic types of scoping: exported and protected.

"Exported" Scope

When a property is defined as exported, it is accessible outside the class. This is the default for FoxPro properties, and doesn’t require any special keywords. Consider the following snippet from the class definition for Customer:

DEFINE CLASS Customer AS Custom
	lNew    = ""
	cName    = ""
	cMail1   = ""
	cMail2   = ""
	cMail3   = ""
	cMail4   = ""
	cMailState = ""
	cMailZip  = ""
Here, we show part of the class definition for the Customer class. All of these properties are exported, which means that they can be directly accessed and assigned by any part of the system that has a reference to a Customer object. In many cases, this is a sufficient and acceptable class design; however, it provides no mechanism for information hiding. In order to achieve encapsulation, we need to use addition scoping options.

"Protected" Scope

Protected properties are similar to exported properties, except that they are only visible to the class in which they’re defined, and its subclasses. In the above class definition for Customer, we may wish to make lNew a protected instance variable, since it is not relevant to the outside interface to the object.

DEFINE CLASS Customer AS Custom
	PROTECTED lNew
		lNew = .T.
	cName    = ""
	cMail1   = ""
	cMail2   = ""
	cMail3   = ""
	cMail4   = ""
	cMailState = ""
	cMailZip  = ""
Scoping of Methods

Most object-oriented languages also allow for the scoping of methods in the same fashion as properties, and FoxPro is no exception. Methods can be scoped as exported or protected. Let’s have another look at our Customer class:

DEFINE CLASS Customer AS Custom
	PROTECTED lNew
		lNew = .T.
	cName    = ""
	cMail1   = ""
	cMail2   = ""
	cMail3   = ""
	cMail4   = ""
	cMailState = ""
	cMailZip  = ""
PROTECTED PROCEDURE VarsFromRec()
	<code>
ENDPROC
PROCEDURE Save()
	<code>
ENDPROC
ENDDEFINE
Note that there is now an exported method called Save(). This method may be called from any routine that has a reference to a Customer object. The method varsFromRec(), which might be called internally, cannot be called from outside the Customer class or one of Customer’s subclasses. In this way, the class definition for Customer is built up, making certain attributes and actions available to everyone, and restricting other attributes, and actions to be used for internal use only.

The Benefits of Scoping in Objects

There are distinct advantages to deliberately hiding information about an object. First of all, this avoids information overload. The object tells strangers what they need to know. Everything else is hands-off. Now, if any of this internal machinery is ever changed, it is important to realize that no changes are required to the way in which the object is used by other parts of the program. The interface is small, clean, and explicit. It is already understood what actions can be performed on a Customer: if the actual varsFromRec() process is changed, we shouldn’t have to concern ourselves as outsiders.

The Public Interface to a Class

The public interface to a class defines what an object looks like to the outside world. Any exported properties and methods are part of the public interface. This interface defines a protocol for interfacing with the object. Any routine wishing to create, access, or modify an object must go through the official, public interface. It’s similar to an API, in that it allows people to use a class and be sure that they won’t have to change their code later, even if the internals of the class change.

It is important to design your objects so that the public interface is resistant to change. That is, it should be possible to change the behavior of an object without having to modify the interface to the object. This will enable all the client code (the external code that uses the object) to continue to work properly, without the need for modification.

Class Libraries

As we develop more and more applications, we begin to build up a library of useful routines. Some companies maintain company-standard function libraries for use by all their developers. There are also many different third-party add-on libraries. Most of us use at least one function library in our applications, and for good reason: they save time. Why waste time writing report routines when you can buy a reporting library that’s already tested and installed in hundreds of other companies?

The problem with traditional function libraries is that you’re limited to what the vendor (or MIS department) provides. Many vendors do not provide source code for their libraries, which means you can’t customize the code in any way.

With class libraries, however, these problems are solved. To customize the code for your own uses, simply subclass the provided classes. You don’t need to have the source code as long as you know the public interface to the class, and the message flow from class to class. Additional information can be retrieved if necessary by instantiating a class and using an object inspector to examine the object’s instance variables and methods.

Class libraries provide functionality for user interface design, financial algorithms, reporting, and many other categories. In fact, most object-oriented languages support a huge market of class libraries, in much the same way that FoxPro supports third-party function libraries.

Frameworks

Frameworks are class libraries that have been designed for a particular business area. They provide generic functionality upon which developers can build, and from which subclasses can be created. Frameworks could be created for graphing, reporting or user interface, for example. They could also be created for life insurance, sales tracking, or store inventory.

Frameworks whose purpose is to help developers build any application are known as application frameworks. These typically provide functionality such as dialog boxes, container classes, and so on. However, the term is often used to apply to any framework. An application framework is a comprehensive set of classes that provide the basic functionality that is common to all applications. Visual FoxPro comes with an application framework that allows you to create windows, menus, toolbars, etc. for your applications. To make our lives even easier, we can use visual tools to manipulate these elements, without having to write the code manually.

Some of the advantages to using frameworks are the same as those of function libraries or third-party products: using tried and tested code without the overhead of trying it and testing it yourself; faster application development; and greater reusability. However, frameworks have the added advantage of allowing you to use just the classes you need and discard the rest rather than calling an add-on product that includes large amounts of functionality that you don’t need.

Conclusion

While object orientation has been called the “wave of the future,” it does involve a learning curve. However, ignore the people who tell you that you’ll have to forget everything you already know and learn from scratch again. In fact, object orientation is mostly an extension of the good modular programming techniques you’re probably already practicing. The difference is that object-oriented languages enforce concepts such as encapsulation instead of leaving it up to our individual consciences!

I hope this paper has succeeded in explaining the basic concepts of object-oriented programming. In case you want to do further reading, I have included a bibliography that lists several books on object-oriented programming, analysis and design.

Enjoy!

Savannah Brentnall is an independent consultant specializing in object orientation and Lotus Notes, and is a founding partner of the Visual Training Group (VTG), which specializes in object technology training. Savannah and her company have recently joined forces with Flash Creative Management to offer VTG’s popular two-day course on object orientation to FoxPro audiences. Savannah is currently a consultant to the Jet Propulsion Laboratory, and her articles have appeared in several Xbase magazines. She has spoken at conferences and user groups around the world, and has programmed in Xbase since 1984. Savannah can be reached by phone at (818) 841-7307, or on CompuServe at 71024,3374.

Appendix A. Glossary of Terms

abstract class A class that has no instances. An abstract class is created only for the purpose of organizing a class hierarchy, or for defining methods and variables that will apply
to lower-level classes. The term “virtual class” is sometimes used to refer to the same concept.

abstract data type A data type that is defined by the programmer and not built into the language. Abstract data types are typically used to create high-level structures that correspond to real-world objects represented in a program.

abstraction The process of focusing on the essential characteristics of an object.

application framework A set of classes that define methods and variables for a generic application, which can then be subclassed to tailor the application for a specific purpose.

base class The most generalized class in a class structure, from which other classes are created. Most applications have many such base classes. Some languages define a primitive base class that serves as the ultimate superclass of all classes.

binding The process of weaving a program together to resolve all the connections among its components. Static, or early, binding resolves these connections before the program is run. Dynamic, or late, binding occurs while the program is running.

cardinality The number of instances that a class may have; the number of instances that participate in a using class relationship.

class A template that defines the methods and variables for a particular type of object; a set of objects that share a common behavior.

class library A collection of generic classes that can be adapted and tailored for a particular application.

class diagram Part of the notation of object-oriented design, used to show the existence of classes and their relationships in the logical design of a system.

class hierarchy A tree structure representing the relationships among a set of classes. Class hierarchies usually have one top node, but may have any number of levels in the tree and any number of classes at each level.

class method A method invoked by sending a message to a class rather than to one of its instances. Class methods usually perform tasks that cannot or should not be performed at the instance level. For example, creating and destroying instances of
a class is something that cannot be done by the instances themselves.

class variable A placeholder for part of the state of a class. Collectively, the class variables of a class constitute its structure. A class variable is shared by all instances of that class.

composite object An object that contains one or more other objects, typically by storing references to those objects in its instance variables.

constructor A method that creates an object and/or initializes its state.

container class A class whose instances are collections of other objects.

data abstraction The process of creating new, high-level data types to serve the needs of a particular application.

derived class See subclass.

destructor An operation that frees the state of an object and/or destroys the object itself.

early binding Static binding. See binding.

encapsulation The bundling, within a class, of data (instance variables) and the code (methods) that operate on that data. Access to the data is permitted only through the object’s own methods. The terms “encapsulation” and “information hiding” are usually interchangeable.

event-driven An event-driven system dispatches events (user actions and system events) to the application, allowing the user navigational control of the interface with the underlying program ready to respond whenever action is appropriate.

hierarchy A ranking or ordering of abstractions. The two most common hierarchies in a complex system are its class structure (the “kind of” hierarchy) and its object structure (the “part of” hierarchy).

identity A distinguishing characteristic of an object that denotes a separate existence of the object, even though the object may have the same data values as another object.

inheritance A mechanism whereby a class can make use of the methods and variables defined in all classes above it on its branch (single inheritance) and/or other branches (multiple inheritance) of the class hierarchy.

instance A member of a class. A class defines the structure of its instances; the class thereby acts as a “factory” for the creation of instances.

instance variable A variable contained within an object, whose value describes properties that the object possesses.

instantiation The process of creating instances from classes.

late binding Dynamic binding. See binding.

message A signal from one object to another, requesting that the receiving object carry out one of its methods. A message consists of three parts: the name of the receiver, the method it is to carry out, and any parameters the method may require in order to fulfill its duty.

metaclass A class whose instances are themselves classes.

method The function or procedure that responds to a message sent by another object. Methods determine how an object will respond to a message it receives.

multiple inheritance A type of inheritance that permits a class to have more than one superclass. The use of multiple inheritance complicates the structure of the class hierarchy, but can sometimes provide more flexibility for defining classes.

name clashing A conflict that can occur in multiple inheritance, when the same method or instance variable is inherited from more than one class.

object A software package containing a collection of related data and methods for operating on that data.

persistence The permanence of an object’s state and relationships.

polymorphism The ability of the same message to be interpreted differently when received by different objects. For example, the message print causes a different series of actions when sent to a diagram than when sent to a text document.

process diagram Part of the notation of object-oriented design, used to show the allocation of processes to processors in the physical design of a system.

rapid prototyping A technique of software development in which a program is developed incrementally as a series of “trial versions” that gradually converge on the desired functionality. Rapid prototyping differs from traditional prototyping because the prototype is not thrown away, but is refined into the deliverable system.

receiver The object to which a message is sent. A sender object passes a message to the receiver object, which processes the message and optionally passes back a return value.

sender The object initiating a message.

single inheritance A type of inheritance in which each class may have only one superclass.

state The values of the attributes of an object at a particular time.

subclass A class that refines or overrides behaviors of its superclass(es). A subclass appears below its superclass(es) in the class hierarchy.

superclass A more abstract version of another class (the subclass). A superclass appears above its subclasses in the class hierarchy.

transition A change of state caused by an event.

use A relationship in which a class manipulates or makes visible the attributes and behaviors of another class.
Appendix B. Bibliography

Booch, Grady.
Object-Oriented Design with Applications.
Benjamin/Cummings. ISBN 0-8053-0091-0

Provides a comprehensive description of object-oriented design methods, using the popular Booch notation. Also includes five real-world application designs, each implemented in a different language. Languages covered are Smalltalk, Object Pascal, C++, CLOS and Ada.

Tkachk, Daniel and Puttick, Richard.
Object Technology in Application Development.
Benjamin/Cummings. ISBN 0-8053-2572-7

Developed at IBM’s International Technical Support Center in San Jose, CA. Covers the current state of object technology, including available object-oriented design notations, visual programming tools, team programming issues, and object databases. One of the few books to give an overview of the woks of the various standards committees, such as the Object Management Group (OMG). Very easy to read.

Meyer, Bertrand.
Object-Oriented Software Construction.
Prentice Hall. ISBN 0-13-629049-3

An old favorite, and still a useful reference. This book explains the idea of “programming by contract.” Source code examples are written in Eiffel.

Mullin, Mark.
Rapid Prototyping for Object-Oriented Systems.
Addison-Wesley. ISBN 0-201-55024-5

Explains the principles of this design methodology by walking the reader through the generation of an actual prototype. Discusses the needs of the client and client-program interaction, as well as actual system features. Language examples are in Smalltalk.

Pinson, Lewis J. and Wiener, Richard S.
An Introduction to Object-Oriented Programming and Smalltalk.
Addison-Wesley. ISBN 020119127

Explains the principles of object orientation in the context of the Smalltalk language. Covers Smalltalk classes, both fundamental and advanced.

Rumbaugh, James; Blaha, Michael; Premerlani, William;
Eddy, Frederick; and Loerensen, William.
Object-Oriented Modeling and Design.
Prentice Hall. ISBN 0-13-629841-9

Describes the authors’ Object Modeling Technique notation. A somewhat academic tone, but includes three case studies.

Taylor, David A.
Object-Oriented Technology: A Manager’s Guide.
Addison-Wesley. ISBN 0-201-56358-4

A guide to object orientation for everyone from managers to developers. Very easy to read, with great illustrations. An ideal book for anyone looking for simple, clear explanations of basic concepts, and especially useful for those who have to convince others of the technology’s merits.

Taylor, David A.
Object-Oriented Information Systems.
Wiley. ISBN 0-471-54364-0

Clear and easy to read. Explains how to plan and implement object-oriented systems, and includes a series of real-world case studies.

Voss, Greg.
Object-Oriented Programming: An Introduction.
Osborne McGraw-Hill. ISBN 0-07-881682-3

Introduces the core concepts of object-oriented programming and shows working examples in C++, Object Pascal, Actor and Smalltalk.

Winblad, Ann L.; Edwards, Samuel D.; and King, David R.
Object-Oriented Software.
Addison-Wesley. ISBN 0-201-50736-6

Explains the key concepts and benefits of object-oriented technology. Gives a “big picture” view rather than concentrating on a particular language. Unlike other books, this one also discusses emerging methodologies and aspects of the technology that are still evolving.

Wirfs-Brock, Rebecca; Wilkerson, Brian; and Wiener, Lauren.
Designing Object-Oriented Software.
ISBN 0-13-629825-7

An easy-to-read guide to object-oriented design, with extensive examples. Also covers the use of CRC cards. Language-independent.