
OODLES
A Full Object Oriented Extension for Clipper 5




Copyright (c) 1993 Rhino Publishing Ltd
All Rights Reserve



SOFTWARE LICENCE AGREEMENT
1.	Definitions
"Software" shall  mean the computer programs contained in the disks in this package, together with any updates subsequently provided by Rhino 
Publishing Ltd.
The term  "Documentation" shall mean all of the printed materials provided in this package or later supplied by Rhino Publishing Ltd.
"Software Copies" shall mean any actual copies or any portion of the computer programs and shall include partial or merged copies as permitted within 
this licence agreement or later supplied by Rhino Publishing Ltd, updates and back-ups.
2.	Licence
Rhino Publishing Ltd agrees to grant the user a non-exclusive and non-transferable licence to use the Software contained herein for internal purposes only. 
The rights granted herein are limited to use of the Software, Software Copies and Documentation as defined within the agreement. All rights not 
specifically granted in this licence are reserved by Rhino Publishing Ltd.
3.		Permitted Uses
The licensee may use the Software in the following ways:
-	Load the Software into RAM and use it on a single workstation or terminal.
-	Install the Software onto a permanent storage device
-	a hard or fixed disk drive.
-	Make up to three (3) back-up copies of the Software.
These copies are for back-up purposes only and the licensee must keep possession of them at all times. Where back-up copies are created, all information 
that appears on the original disk labels must be copied onto the back-up labels. This includes the copyright notice.
-	Modify the Software, merge it into another program or incorporate and distribute it in any standard Clipper executable files which you are then 
at liberty to distribute.
-	Copy the programs' source code in printed form for the purpose of modification and support in your use of the Software. The licensee must 
keep possession of the print-out at all times.
4. Prohibited Uses
You may not:
-	Use this Software across a network. Each programmer must be an original licensee i.e. he must purchase his own copy of the product.
5. Limitations
This licence grants the user limited rights to use the Software, Software Copies and Documentation as expressly provided in this licence. Rhino Publishing 
Ltd retains title to all the Software, Software Copies and Documentation. The licensee may not distribute copies of the Software or Documentation to 
others.
The licensee agrees to protect the Software, Software Copies, Documentation and source code from unauthorised publication, use, reproduction or 
distribution. Under no circumstances must you attempt to rewrite, decompile, disassemble or reverse-engineer any of the object modules. Rhino Publishing 
Ltd retains title to the source code at all times. Modification or rewriting of the source code does not give you rights of ownership. You may only own your 
source code by starting from scratch and writing your own original code.
Any Rhino Publishing Ltd proprietary right notices must not be obscured.
All rights not specifically granted in this licence are reserved by Rhino Publishing Ltd.
6. Term
This licence is effective from the day you open the package and use the Software and Documentation contained therein. It continues for twenty-five (25) 
years or until you destroy the entire contents of this package and any Software Copies.
This licence will terminate if the licensee fails to comply with any term or condition of the agreement. Upon such breach, Rhino Publishing Ltd reserves 
the right to terminate the licence upon notification in writing and to seek the remedies of injunction and other equitable relief in addition to any other 
remedies which may be available to the Company. Upon termination, the licensee will be required to return all copies of the Software and Documentation 
to Rhino Publishing Ltd. In these circumstances the licensee will not be entitled to any refund for amounts paid for the Software.
7. Limited Warranty
Rhino Publishing Ltd warrants to the original licensee that disks on which the computer programs are recorded are free from defects in workmanship and 
materials under normal use and service for a period of ninety (90) days from the date of delivery as evidenced by a copy of your receipt or invoice. Rhino 
Publishing Ltd's entire liability and your exclusive remedy shall be replacement of the disk not meeting Rhino Publishing Ltd's limited warranty and which 
is returned to Rhino Publishing Ltd with a copy of your dated receipt or invoice. If failure of the disk(s) has resulted from misapplication of the product, 
accident, abuse, unauthorised modification or theft, then Rhino Publishing Ltd shall have no responsibility to replace the disk(s) under this limited 
warranty.
Entire risk as to the results and performance of the program shall be assumed by the licensee. Should the program prove defective, the licensee shall 
assume the entire cost of all necessary servicing, repair or correction. Should a disk become damaged during the warranty period, Rhino Publishing Ltd 
will replace it for a replacement fee of  10.00. To replace a disk damaged by the customer during the warranty period, please send the disk itself, a copy 
of your dated receipt or invoice indicating proof of purchase and a cheque for 10.00 to:-
Rhino Publishing Limited
PO Box 255, Doncaster, DN4 7AW, England.
The licensee must insure or assume the risk of loss or damage in transit to any defective item being returned.
8. Other Limitations
EXCEPT AS SET OUT ABOVE, RHINO PUBLISHING LTD DOES NOT WARRANT, GUARANTEE OR MAKE ANY REPRESENTATION 
REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THE PROGRAM IN TERMS OF, ACCURACY, RELIABILITY, 
CORRECTNESS OR OTHERWISE. THE LICENSEE RELIES ON THE PROGRAM AND ITS RESULTS SOLELY AT HIS OWN RISK. THE 
ABOVE IS THE ONLY WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
IMPLIED WARRANTIES OF THE MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE THAT IS MADE BY Rhino 
Publishing Ltd ON THIS PRODUCT.
NEITHER RHINO PUBLISHING LTD NOR THEIR AGENTS SHALL BE LIABLE FOR SPECIAL, CONSEQUENTIAL, INDIRECT OR OTHER 
SIMILAR DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
In no event shall our liability for any damages to you or any other person exceed the price paid for the licence to use the software, regardless of any form of 
the claim.
Additional statements by agents, employees, distributors or dealers of Rhino Publishing Ltd do not constitute warranties or conditions by Rhino Publishing 
Ltd, are not binding upon Rhino Publishing Ltd and should not be relied upon.

This agreement shall be governed by the laws of England and Wales.

You acknowledge that you have read this Agreement, understand it and agree to be bound by its terms and conditions. Furthermore, you agree that this is 
the complete and exclusive statement of Agreement between us and supersedes all prior Agreements, verbal or written, any proposals and other 
communications between us relating to the subject matter in this Agreement.


Contents

1.	Installation	1
2.	Introduction	1
3.	Compiling and Linking	1
4.	Debugging	1
5.	Tutorial	2
6.	Supplied Samples	6
6.1.	Point	6
6.2.	Box	6
6.3.	BoxShad	6
6.4.	BoxSize	6
6.5.	BoxClr	7
6.6.	Saver	7
6.7.	Cust	7
6.8.	Record	7
6.9.	Window	7
6.10.	Menu	8
7.	Terminology	8
7.1.	What is an Object ?	8
7.2.	Class	8
7.3.	Method	9
7.4.	Instance Variable	10
7.5.	Inheritance	11
7.6.	Polymorphism	11
7.7.	Encapsulation	12
7.8.	Parent Class	12
7.9.	Derived Class	12
8.	Commands	13
8.1.	Class <className> [ Inherit <super> ]	13
8.2.	Var <V1> [, <Vn> ]	13
8.3.	Message <name> [ method <mName>]	14
8.4.	End Class	14
8.5.	Method <name>( [ , <Pn>] )	15
9.	Functions	16
9.1.	super( )	16
10.	Built in Methods	16
10.1.	oClone( <obj> )	16
11.	Implementation Details	17
12.	Technical Support	17


1.	Installation
Installation is very easy.
o	Copy the OODLES disk along with its sub directories to a new sub directory.
o	Copy the OODLES.LIB file to your library directory (This file is in the OODLES\LIB directory) OR 
add the OODLES\LIB directory to your LIB environment.
o	Copy the supplied OOPS.CH file ( found in the OODLES\INCLUDE directory ) to your include 
directory OR add the OODELS\INCLUDE directory to the INCLUDE environment variable.
o	Copy the supplied Norton Guides (in the OODLES\NG directory) to your NG directory.
You are now installed
2.	Introduction
The underlying goal of OODLES is to realise the  power of object oriented programming with Clipper 5.x but to keep 
the implementation as simple as possible. The learning curve for OODLES is small, with only a few new commands 
and concepts to learn. We have included some sample objects in the tutorial section and a real world menu example, 
complete with source code.
The advantages of objects and object oriented programming have been hammered into programmers for many years. 
We have produced a product which allows object oriented techniques to be freely mixed with more traditional 
procedural programming practices. You may start by adding a single object to an existing application allowing you to 
start small and add more objects as you become more confident.
There is very little new within object oriented programming. It does, however, guide you towards better programming 
techniques. Although these same techniques may be used without an object oriented implementation.
When learning object oriented programming the most common question asked is "what do I turn into an object ?" . As 
database programmers you have a head start. This question has the same answer as "What fields do I put into a 
database ?". As database programmers you can reuse all your knowledge of database design when designing objects.
3.	Compiling and Linking
There is nothing special about source code containing object definitions. You must, however, have the include file 
"OOPS.CH" when compiling and the library file "OODLES.LIB" when linking.
Make sure that your INCLUDE environment variable has the OODLES\INCLUDE directory OR that you have copied 
the file OOPS.CH to your standard include directory.
Make sure that your LIB environment variable has the OODLES\LIB directory OR that you have copied the file 
OODLES.LIB to your standard include directory.
4.	Debugging
The Clipper debugger is fully supported by OODLES. Create an object, say a local, monitor locals, locate the object 
with the debugger (tab onto variables) and hit return twice. The debugger brings up a list of the instance variables for 
this object. You may cursor down to any one of them and hit return to change the values, just as you can with an 
array.



5.	Tutorial
Most people learn well by example. We have supplied several sample objects. Some are for learning purposes only 
(the point and box classes) others can be used right away (saver, record, menu). We will discuss the box class in this 
section and a couple of the derived classes (boxClr and boxShad).
We are using the BOX class because it is a very visual example. You can actually compile link and watch the results.
Make sure that the software has been properly installed and that the compiling and linking recommendations have 
been followed.
Lets start by building the BOX sample code by typing the following in the sample directory:
build box

We can then run the compiled output TBOX.EXE, press the up, down, left and right arrow keys to move the box 
around the screen. Press the ESC key to quit.

Let's take a closer look at the source code for the box class.
The first part is the definition of the box class, the "oops.ch" include file must be used. We are also using the Clipper 
supplied "box.ch" file which defines various box styles.

#include "oops.ch"				// required for oops syntax extensions
#include "box.ch"					// box drawing characters

// start the class definition
class box
	var nTop								// Somewhere to hold the coordinates
	var nLeft

	var nBottom
	var nRight

	var char											// fill character

	message init( t, l, b, r)				// initialise the object

	message up( )									// move the box up
	message down( )								// move the down
	message left method moveleft( )		// left is reserved word
	message right method moveright()		// right is reserved word

	message display()

end class

Now we have to code the methods. let's start with the initialisation method. Initialisation methods should be called 
whenever objects of the class are created.
method init( t, l, b, r )
	::nTop := t
	::nLeft := l
	::nBottom := b
	::nRight := r
	::char := ""					// default to a point
return( self )					// always do this in an initialisation 
routine

The init method receives the top,left,bottom and right coordinates of the box. It then copies those parameters into the 
instance variables, it also sets the char instance variable. An initialise method almost always returns self.


The up method moves the top and bottom of the box up one line.
method up( )
	::nTop --
	::nBottom --
return( self )

Again, we are returning self, this means we can cascade methods.
Cascading means having more than one message send at the same time:-
oBox:up():down():display():up():display()

We now do the same for the rest of the movement methods.
method down( )
	::nTop ++
	::nBottom ++
return( self )

method moveRight( )
	::nRight ++
	::nLeft ++
return( self )

method moveleft( )
	::nRight --
	::nLeft --
return( self )

We now need to implement the display method.

method display( )
	@ ::nTop, ::nLeft, ::nBottom, ::nRight box B_DOUBLE+::char
return( self )

We now need some code to drive the object.
This uses the Clipper supplied "inkey.ch" include file.
We first create a box object by calling the box( ) function. This function is created by the Class command. It returns 
an object of that class. We then immediately initialise the object via the init( ) method. If any initialisation is to be 
done it is highly recommended that you do it in this manner. Leaving it until later is prone to errors when you "forget" 
to initialise the object.

#include "inkey.ch"

function tbox
	local oBox, nKey
	// first create a box object

	oBox := box():init(2,2, 10, 10)

	// pass it onto the moveIt handler
	cls
	while (nKey := inkey(0) ) != K_ESC	// Get a key
		moveIt( oBox, nKey )					// process the key
		oBox:display()								// display the box again
	end
	cls
return( nil )

The moveIt( ) function takes the object as a parameter, along with a key to process. We implemented it this way to 
show that Objects can be passed to functions just like other variables.

function moveIt( o, nKey )
	do case
	case nKey == K_UP
		o:up()						// If it is the up key move up

	case nKey == K_DOWN
		o:down()						// If it is the up key move down

	case nKey == K_RIGHT
		o:right()						// If it is the up key move right

	case nKey == K_LEFT
		o:left()						// If it is the up key move left

	otherwise
		o:char := chr( nKey )	// Change the key for the background
	end case
return( nil )

You will note that the reserved words, right and left, are not a problem when using the objects. The message right and 
left are not reserved whereas methods of that name are.
Note: When the object is passed to the moveIt( ) function, it is not copied. Objects behave exactly as arrays. A 
reference to the original object is passed, not a copy of the object. This means that any changes to the instance 
variables of that object changes the original Object (because its actually the same object).
We have now created our first object and some source code to drive it. Study the rest of the supplied samples and start 
creating your own objects. You can start by adding a single object into existing applications. As you gain more 
experience you will start to create your own library of classes which get used in all your new applications.
We will now look at one of the main benefits of OOPS, reusable code. We will create a new class based on the box 
class, the BoxSize class, a sizeable box.
The source code starts the same by including the "oops.ch"
However, the class statement now has the inherit clause. This means we want to create a new class definition but we 
want all the characteristics of the box class as a starting point. That means we get all instance variables and methods 
of the box class by default.
#include "oops.ch"							// required for oops syntax 
extensions

class boxSize inherit box
	message sizeUp()				// add sizeing methods
	message sizeDown()
	message sizeLeft()
	message sizeRight()
end class

again we now need to code these new sizeing methods.

method sizeUp
	::nBottom --
return( self )

method sizeDown()
	::nBottom ++
return( nil )



method sizeLeft()
	::nRight --
return( self )

method sizeRight()
	::nRight ++
return( self )

Now some code to test this new class with. 
The tBoxSize code is identical to the tBox code, additions to movIt( ) have been made to handle sizing.
#include "inkey.ch"
#define K_CTRL_UP		397
#define K_CTRL_DOWN	401

function tBoxSize
	local oBox, nKey
	// first create a box object

	oBox := boxSize():init(2,2, 10, 10)

	// pass it onto the moveIt handler
	cls
	while (nKey := inkey(0) ) != K_ESC
		moveIt( oBox, nKey )
		oBox:display()
	end
	cls
return( nil )

function moveIt( o, nKey )
	do case
	case nKey == K_UP
		o:up()
	case nKey == K_DOWN
		o:down()
	case nKey == K_RIGHT
		o:right()
	case nKey == K_LEFT
		o:left()
	case nKey == K_CTRL_UP
		o:SizeUp()
	case nKey == K_CTRL_DOWN
		o:sizeDown()
	case nKey == K_CTRL_RIGHT
		o:sizeRight()
	case nKey == K_CTRL_LEFT
		o:sizeLeft()
	otherwise
		o:char := chr( nKey )
	end case
return( nil )

This example just shows inheriting and extending. We now want to look at inheriting and overriding some existing 
methods.


Let's look at the boxClr class. This inherits from the boxSize class and then overrides the existing method for display.

#include "oops.ch"							// required for oops syntax 
extensions

class boxClr inherit boxSize
	message display							// override existing method
end class

method display()
	cls
	::super():display()						// call the existing method
return( self )

The only new thing here is the ::super( ):display(), instead of sending the display method to self, we send it to the 
parent of self, in this case the boxSize class (which actually calls the box display method).
6.	Supplied Samples
To build any of the supplied examples run the supplied batch file BUILD.BAT, passing the name of the sample you 
want to compile and link. To build them all run the batch file BUILDALL.
Example:
build point
to build the point sample
or
Buildall
to build all supplied samples
6.1.	Point
The Point class is a basic class designed to show a visible point on the screen. It is supplied for learning purposes 
only. It has an associated Tpoint.prg source file which creates and drives a point object.
6.2.	Box
The Box class has been provided for learning purposes only. It is a base class (it does not inherit from any other 
class), it is however a parent class for BoxShad.
It has an associated tBox.prg source file which drives the box class. You may press the up, down, right and left keys 
for box movement. The escape key quits and any other key changes the background character.
6.3.	BoxShad
The BoxShad class is derived from the Box class and has been provided as an example of inheritance. It overrides the 
box display method and makes calls to the box display (via the method super( ) ).
It has an associated tBoxShad.prg source file which drives the boxShad class. You may press the up, down, right and 
left keys for box movement. The escape key quits and any other key changes the background character.
6.4.	BoxSize
The BoxSize also inherits from box but only adds methods, it does not override any existing methods. This class adds 
the ability to size the box.
It has an associated tBoxSize.prg source file which drives the boxSize class. You may press the up, down, right and 
left keys for box movement. You may also size the box by pressing control-up, control-down, control-right and 
control-left. The escape key quits and any other key changes the background character.


6.5.	BoxClr
The BoxClr class inherits from BoxSize and overrides the display method. This class shows that it is possible to 
override methods which have already been overridden. You may press the up, down, right and left keys for box 
movement. You may also size the box by pressing control-up, control-down, control-right and control-left. The escape 
key quits and any other key changes the background character.
6.6.	Saver
The Saver class is the first real world class, it can actually be used in applications right away. It saves the current gets, 
the screen and the colour in an object. It gives an example of where several things "belong" together, that is, the gets, 
colour and screen text "belong" together. Instead of using an array or several variables a single object can be used to 
store these and hold them together.
It has an associated tSave.prg source file which drives the saver class. 
6.7.	Cust
The Cust class shows a "one time object", that is, an object created specifically for a particular application. It handles 
a customer file and has an instance variable for each field in the file. It has a method for loading the fields into the 
instance variables and one for saving them to disk again. It also has a display( ) method and edit( ) method.
It has an associated tCust.prg source file which drives the Cust class. 
The Cust class inherits from a standDbf. With more work this object could be used as the only mechanism for 
handling the customer file. If it was ever required to move to another storage mechanism (like SQL or an AS/400) 
then the only changes to the application could be to inherit from an SQL class or an AS400 class.
6.8.	Record
The Record class can hold a copy of a record. It can compare the current record with the current contents of the object 
and, if required to overwrite the current record with the current contents of the object.
It is similar to a scatter/gather mechanism. With a little more work, it could be used to handle named fields, or a list 
of fields to scatter/gather.
It has an associated tRecord.prg source file which drives the Record class.
6.9.	Window
The Window class is more complicated than the previous classes. It shows that instance variables can hold arrays and 
even other objects. It consists of a window (inherited from box) with an array of rows and an array of columns, used to 
place gets in the window. It also has an instance variable to hold a record object.
It has an associated tWindow.prg source file which drives the window class. The source code for this should be 
studied before running the tWindow executable. After you finish the edit (with a normal control-W or Escape) you 
may press several movement keys, up, down, right and left. You may also press F3 to edit the data and F4 to save it to 
disk.


6.10.	Menu
The menu class is the second "real world" example. It is a fairly sophisticated pull down and pop up menu system, 
complete with source code. To make menu's simple to use we have added an include file (called menu.ch) which 
makes menus easy to read.
For example:
MENU MyMenu
	POPUP "&File"
		INCLUDE FileMenu
	END POPUP
	INCLUDE Record
	POPUP "&Format"
		INCLUDE Format
	END POPUP
END MENU

shows how easy it is to create a menu

It has an associated tMenu.prg source file which drives the Menu class.
Once the menu is created it may be used in two ways.
As PullDown
	oMenu:Mode := STYLE_PULLDOWN
Or as PopUp
	oMenu:Mode := STYLE_POPUP

The Menu class is reasonably advanced in the implementation. However, you are not required to understand the class 
definition before using the class. That is one of the main benefits of Objects (and libraries), you can use predefined 
classes without looking at the implementation of those classes.
7.	Terminology
7.1.	What is an Object ?
An object resembles a normal variable in that it contains data.  In addition, it understands how to perform actions 
(methods) and so contains both data and code. The data is held in instance variables and the code is held in methods. 
An object has characteristics (a Point has a row and a column), these characteristics are called instance variables. 
You can also tell objects to do something, this is achieved by passing it a message (and optionally some parameters). 
This is where an object differs from other variable types. 
7.2.	Class
CLASS is similar in concept to TYPE. An object belongs to a class, that is all point objects belong to the class point. 
This is like saying all numerics have type numeric. All objects have a type of "O", just like all numerics have a type of 
"N". However, with many different kinds of objects we use class to say what type of object the variable belongs to.


7.3.	Method
Methods are actions performed on the objects. 
Instead of passing the data to the function, the function (called a method) is passed to the Object.
Functional programming :-
a := 10
? sq( a )		// passes a to the function sq()
function sq( n )
	local temp
	temp := n * n		 // perform the action
return( temp )

Methods :-
a := number( ):init(10)		// Returns an Object
? a:sq()			// call a method "built into" the Object definition

Class number
	Var n		// Give the Object the data item "n"
	message init(x)
	message sq
end class
method init( x )
	::n := x
return( self )
method sq
return( ::n * ::n )

Creation function often confuses programmers who are unfamiliar with Objects. However, it is not unusual to call a 
function to "create" a variable. For example a call to either date() or ctod() is required in the creation of a DATE 
variable.
These two styles differ in that the first passes the data to a function and the other sends a message to the data..
The ':' operator is used to separate the Object from the message. This message can mean a method or an instance 
variable.


7.4.	Instance Variable
An Object stores data in an instance variable.
For example two variables are required for an object to describe a POINT on a screen, a ROW and a COLUMN. So, a 
Class definition could look like this :-

#include "oops.ch"
Class POINT
	var row, col
	message init(x, y)		// initialise the point class
	message up
	message down
	message right	method oRight	// right is a reserved word
	message left	method oLeft	// left is a reserved word
end class
Method init( x,  y)
	::row := x
	::col := y
return( self )
Method up
	::row--		// decrement the row.
return( self )
Method down
	::row++		// increment row.
return( self )
Method Right
	::col++		// increase the column
return( self ) 
method left
	::col --		// decrement the column
return( self )

SELF is the OBJECT that the message (method) is sent to. It helps when coding to have the concept of SELF.
Instance variables in Clipper 5 can be read only or assignable. The instance variables are accessed via the ':' operator.
You may think of this as a "send" operator.
obj : message => send the message to the Object.
instance variables can be accessed in the same manner as other variables, the only difference is the object must be 
specified:-
x := obj:row		// reads the instance variable "row"
obj:row := 4		// Assigns the value 4 to the instance "row"


7.5.	Inheritance
Inheritance enables the definition of one object to be made in terms of an existing one. It is very common to require 
new data types with the same characteristics as existing data types but with minor changes.
Imagine defining the Class for ThreeD, a three dimensional Point.
Having previously defined the POINT Class we now require  "additional information" (another instance variable) and 
some "additional methods" (moving around in the extra dimension). 

Class ThreeD Inherit Point
	var Depth		// add the instance variable to the ThreeD
	message in
	message out
end class

Method In			// add method
	depth--
return( self )

Method Out
	depth++
return( self )

The Class ThreeD has 3 instance variables: ROW and COL ( from the Class definition of Point) and DEPTH (defined 
here). It also inherits all methods from the Point Class.
In other words once the Point Class has been defined it is easy to build a new Object Class based on it. If bugs are 
found in the original code for Point, fixing them would automatically fix the ThreeD Class.
This is one of the most powerful extensions to "normal" procedural programming. It is likened to building a function 
library where new functions are defined in terms of existing functions. If bugs are fixed in the primitive functions, 
bugs in dependent functions are fixed. 
7.6.	Polymorphism
Polymorphism is the ability to send the SAME message to different types of data (Objects).
Although this can be mimicked in ordinary function calls, the code tends to become unmanageable:-
Functional solution:

a := 10
? sq( a, 'N', 'N' )	// print the square of a numeric
a := '10'
? sq ( a )				// Same function call for different data type

The code for this is :-

function sq( x )
	local temp
	do case
	case valtype(x) == 'C'
		x := val(x)
		temp := x * x
	case valtype(x) == 'N'
		temp := x * x
	endcase
return( temp )

Should support for Dates or Arrays be required with 20 or so mathematical functions, all 20 functions would require a 
similar case statement.
OOPS resolves this problem. When a message is sent to an Object, the run time engine (with late binding) determines 
the method to use. I.e. the language does this work for you. Once in place, it is possible to send the SAME message to 
two different Classes of Objects and the language will decide the code to execute.
See the supplied samples in BOX, BOXSHAD, BOXSIZE and BOXCLR. This shows objects of different classes 
receiving the same message.
7.7.	Encapsulation
Encapsulation permits the building of "shells" around the data. This concept has been around for years. Eg. an 
interface that programmers must use to access the data. 
7.8.	Parent Class
When a new class is created based on the definition of an existing class the existing class is called the parent class. 
Changes to the parent class are automatically inherited by the new class (called a derived class).
example:
#include "oops.ch"

class point
	var nRow, nCol
end class

class threeD inherit point
	var nDepth
end class

The Class threeD inherits from the parent class point. Any changes to the point class are automatically inherited by 
the new class threeD.
7.9.	Derived Class 
When a new class is created based on an existing class that new class is called a derived class. It automatically 
inherits all the attributes of the parent class. If methods are "added" to the derived class which were present in the 
parent class then the new methods override the existing definition.
example:
#include "oops.ch"

class point
	var nRow, nCol
	message display() method pDisp()
end class

method pDisp()
	@ ::nRow, ::nCol say "."
return( self )

class threeD inherit point
	var nDepth
	message display()
end class
method display()
	@ nRow, nCol say chr( ::nDepth )
return( self )

The Class threeD inherits from the parent class point. Any changes to the point class are automatically inherited by 
the new class threeD. Any changes to existing methods are overridden in the new class threeD.


8.	Commands
8.1.	Class <className> [ Inherit <super> ]
Start the definition of a new class
Syntax
Class <className> [ Inherit <parent> ]
Arguments
<ClassName> is the name of the new class to define
<super> is an optional parent class.
Description
Start a new class definition. The syntax is supported by the supplied file "oops.ch" which must be included before the 
class definition.
You must have a corresponding "End class".
Example:
#include "oops.ch"

Class Point
	var row, col
	message up()
	message down()
end class

See Also:
End Class
8.2.	Var <V1> [, <Vn> ]
Define the name of an instance variable or several instance variables.
Syntax
Var <V1>[, <Vn>]
Arguments
<V1> is the name of an instance variable.
<Vn> can be one or more instance variables to add.
Description
Add the instance variables to the class definition.
The command must only be used with the class definition. That is between the "Class" and "End Class" definitions.

Example:
#include "oops.ch"
Class Point
	var nRow, nCol
	...
	message up
	...
End Class
See Also:
Class, End Class.

8.3.	Message <name> [ method <mName>]
Add a message to the class definition
Syntax
Message <name>( [,<Pn>]) [method <mName>]
Arguments
<Pn> is an optional list of parameters for the method
<mName> is an optional method name to map the message onto.
Description
Add a message to the class definition. If parameters are required they must be defined. The optional <mName> is 
normally only used to avoid reserved name conflicts. You may map a message onto a method of a different name. It is 
also used when two classes have a common method name and are in the same source file.
Example:
#include "oops.ch"
Class Point
	var nRow, nCol
	message up()
	message down()
	Message right() method oRight()	// avoid the reserved name 
conflict
	message left() method oLeft()
	message fastup( nRows )				// parameter to move up xRows
End class

See Also:
Class, End Class, method
8.4.	End Class
Finish the class definition
Syntax
End Class
Arguments
None
Description
Finish the class definition, create the class and return an object of that class to the calling program.

Example:
#include "oops.ch"
Class Point
	var nRow, nCol
	message up()
	message down()
	Message right() method oRight()	// avoid the reserved name 
conflict
	message left() method oLeft()
	message fastup( nRows )				// parameter to move up xRows
End class

See Also:

8.5.	Method <name>( [ , <Pn>] )
Start the code for a method.

Syntax
Method <name>( [ , <Pn> ]  )

Arguments
<Pn> is a list of parameters passed to the method.

Description
Methods are implemented via static functions, that is, functions local to the file they are defined in. Methods are, 
therefore, almost identical to functions.
The return values should always be considered, if you wish to send multiple messages to the same object then it is 
essential that "self" is always returned.

Example:
method up()
	::row - - 
return( self )
method moveLeft()
	:: col - - 
return( self )

allows code to be written as :-

oPoint:up( ):moveLeft():display():up():moveLeft():display( )
rather than
oPoint:up( )
oPoint:MoveLeft( )
oPoint:display( )
oPoint:up( )
oPoint:moveLeft( )
oPoint:display( )
 
See Also:
Message



9.	Functions
9.1.	super( )
Call the method for the parent class.
Syntax
::super( ):up()
Arguments
none
Description
To maximise code reuse, it is often necessary to override a message from the parent class, a special mechanism is 
therefore required to call the parents method of the same name.
Example:
#include "oops.ch"
class boxClr inherit box
	message display()	// override the box display message
end class
method display()  
	cls
	::super:up()		// call the method up found in the parent class
return( self )
See Also:
message, method

10.	Built in Methods
10.1.	oClone( <obj> )
Make a clone of the Object
Syntax
oClone( <obj> )	--> clones object
Arguments
<obj> is the object to clone
Returns
A clone of the passed object.
Description
When objects as passed to functions or assigned to other variables, a reference to the original object is actually 
created. This means that the two variables refer to the same object. Change one and the seconds reflects that change. 
It is often required to break this link between the variables and to create a new object identical to the original but 
without the link. oClone does just that, it creates a new object of the same class and copies the contents across.
Example:
#include "oops.ch"
class boxClr inherit box
	message display()	// override the box display message
end class
method display()  
	cls
	::super:up()		// call the method up found in the parent class
return( self )
See Also:
message, method
11.	Implementation Details
When the Clipper compiler matches the special send operator ( the ":" character") it generates code to search for an 
associated method for that object at run time.
Example:
oMenu:execute()
The object oMenu belongs to a class which contains a method execute. OODLES arranges for these messages to be 
mapped onto codeblocks at run time. The codeblocks are generated automatically within the supplied commands 
which build the objects (defined in the OOPS.CH file).
Internally OODLES keeps an array of these codeblocks for each class. OODLES accesses and executes these 
codeblocks from C. OODLES was originally designed to work with Clipper 5.2 which has mechanisms to execute 
codeblocks from within C or assembler. To make  OODLES work with Clipper 5.01 we have had to implement this 
ability.

Methods are implemented via static functions. This means that no two methods may have the same name within the 
same source file. You may use the message__method mechanism to override this.
We have implemented messages via codeblocks. Internally, the message command creates a codeblock and passes this 
to a function for possible future execution. To simplify this we have created a command which takes a message and a 
codeblock. If you are concerned about future porting to CA:Visual Objects then avoid this construct within day to day 
programming. 
For completeness the syntax is:-
message <name> action <codeBlock>
<Name> is the message name
<codeBlock> is a codeBlock which is executed if that object receives a message of that name. 
Example:
message doit action { |self, x, y| myFunction( self, x, y ) }
...
function myFunction( self, x, y )
	...
return( self )

Using this message:
oMine:doit( 5, 6 )

The parameter x recieves 5, y recieves 6 and self is passed to the codeBlock by OODLES.

12.	Technical Support
Your first port of call should be the distributor or dealer you purchased this product from. If they are not able to 
immediately help they will contact us for assistance. They should return to you with the answer.
If you purchased directly from Rhino Publishing, or if you have purchased a Rhino Publishing support contract then 
fax us on (+44) 302 371 710. Or Phone us on (+44) 302 371 711.





Copyright (c) 1992, 1993 Rhino Publishing Ltd. All Rights Reserved
Page: 17



Copyright (c) 1992, 1993 Rhino Publishing Ltd. All Rights Reserved
Page: 1


