
                      1. INTRODUCTION TO OBJECT ORIENTATION

1.1. Object Orientation and Clipper 5.01
     
     Object orientation and object-oriented programming (OOP) is at present
     revolutionizing the programming landscape. Until relatively recently,
     however, this subject would not have been of immediate interest to
     Clipper programmers, since Clipper 5.01 does not provide the features
     necessary to implement OOP. Most importantly, while Clipper provides
     four predefined object classes (TBrowse, TBColumn, Get and Error), it
     does not provide the ability to create one's own object classes, or
     user-defined objects (UDOs). Because of this, for Clipper programmers,
     OOP was more of a dream to which we could only aspire, than an
     attainable goal.
     
     Fortunately, the outlook for OOP in Clipper changed with the
     introduction of Class(y). Class(y) actually extends the Clipper 5.01
     language, providing a comprehensive range of features designed to
     support true object-oriented programming.
     
     Class(y) enhances Clipper 5.01 by providing the ability to create and
     use user-defined object classes, allowing fully object-oriented
     programs to be developed. It provides all the key features of an
     object-oriented language, including encapsulation, inheritance and
     polymorphism.
     
     Class(y) combines the best object-oriented features of C++ and
     Smalltalk with the database power of Clipper 5.01, and adds some
     uniquely powerful capabilities of its own. As a result, Clipper with
     Class(y) stands alongside C++ as one of the very few object-oriented
     languages capable of being used for practical commercial application
     development.
     
     How does Class(y) work?  In the Clipper library, there is a module
     which is used internally to create the predefined object classes. This
     module is also responsible for handling messages sent to these
     objects. Class(y) replaces this module completely. The replacement
     module provides object-oriented capabilities not found in standard
     Clipper, such as the ability to create UDOs, and other features
     designed to support true object-oriented programming. The replacement
     module has been written in C and assembly language, and is optimized
     for high performance.
     
     The new features work totally transparently, allowing the creation of
     user-defined classes which can be then used in exactly the same way as
     Clipper's predefined classes.
     
     To use Class(y) effectively, an understanding of the concepts involved
     in object orientation is required. In the next section, we will
     examine object orientation in general. This will be followed by
     practical examples using Class(y).

1.2. An overview of object orientation
  
         "After years of relative obscurity, object orientation
          appears to be entering the mainstream of commercial
          computing for both software developers and end users. A
          shift to object orientation is occurring simultaneously
          across a wide range of software components, including
          languages, user interfaces, databases, and operating
          systems. While object-oriented programming is no
          panacea, it has already demonstrated that it can help
          manage the growing complexity and increasing costs of
          software development".
     
               - from Object-Oriented Software by Winblad, Edwards & King
     
     The above quotation is an excellent summary of what is happening in
     the world of computing today. Although exciting research and
     development is taking place on many fronts, no single software topic
     currently enjoys as wide a scope or impact as object orientation. Some
     of the most advanced and powerful software products available today
     incorporate object orientation as a central concept: languages such as
     Smalltalk, C++, and Actor; leading edge minicomputer databases such as
     Servio Logic's Gemstone and Ontologic's Ontos; expert system
     development tools such as Neuron Data's Nexpert Object and Level 5
     Object from Information Builders; and graphical user interfaces (GUIs)
     such as Microsoft Windows 3.0, GeoWorks' PC/GEOS and QuarterDeck's
     DESQview/X, as well as UNIX GUIs such as Open Software Foundation's
     Motif, and Sun Microsystems' Open Look.
     
     Although object orientation applies in slightly different ways in each
     of these areas mentioned above, the same basic concepts are being
     applied in each case. Because of its broad scope, the term is often
     misused, especially in marketing claims; indeed, an entire article has
     been written on this subject ("My cat is object-oriented", by Roger
     King of the University of Colorado).
     
     This abuse often arises from the fact that object orientation in user
     interfaces is not easy to define clearly, and it is through user
     interfaces that end users encounter object orientation, usually
     without realizing it. Some vendors assert that their products are
     object-oriented merely because they use screen windows - the windows
     are objects, so the argument goes, and therefore the program is object
     oriented.
     
     This is perhaps an extreme of misrepresentation, but the situation is
     complicated by in-between products such as Microsoft Windows. At the
     user interface level, Windows arguably does not present any
     particularly obvious object-oriented features to the user, but its
     operation at the programming level is object-oriented enough to
     integrate well with object-oriented languages.
     
     The aspect of object orientation which Class(y) addresses is that of
     object-oriented languages. The features required of an object-oriented
     language are well defined, and existing language products set
     something of a standard in this area. Once familiar with the
     principles of object-oriented languages, it becomes much easier to
     differentiate between true and false claims about object orientation
     in other areas.
     
     One of the main driving forces for the adoption of OOP is likely to be
     the need to produce programs that run under graphical user interfaces
     such as Microsoft Windows. This means that changing from procedural to
     object-oriented programming may involve changing not just the language
     being used, but the operating environment, resulting in an extremely
     steep learning curve.
     
     While GUIs promise to make life easier for the end user, they will
     only make it harder for the programmer, unless we are prepared to
     change our programming style. Writing programs with a completely
     object-oriented architecture simplifies development for GUIs, since
     the program architecture reflects the architecture of the underlying
     environment.
     
     Although we cannot write Clipper applications for Microsoft Windows
     just yet, we can prepare ourselves by starting to develop object
     oriented programs. This will allow us to climb the learning curve
     gradually, rather than suddenly being forced to learn a new
     programming style as well as the complexities of event driven
     programming in a GUI.
     
     We'll start our climb of the learning curve with a brief look at the
     history of object-oriented languages, followed by an introduction to
     object-oriented concepts.

1.3. A brief history of object-oriented languages
     
     The concept of an object class and inheritance, central to object
     oriented languages, was first implemented in the language Simula 67,
     an extension of Algol 60 designed in 1967 by Ole-Johan Dahl and
     Krysten Nygaard from the University of Oslo and the Norwegian
     Computing Center (Norsk Regnesentral). Although Simula, as it is now
     called, is a general purpose programming language, it is not in wide
     usage.
     
     The major milestone in the development of object-oriented languages
     was the Smalltalk research project at the Xerox Corporation's Palo
     Alto Research Centre (PARC). Starting in the early 1970s, the
     Smalltalk project, initiated by Alan Kay, had as its goals more than
     just the development of a programming language; rather, a complete
     integrated environment was the goal, including an object-oriented
     language, development tools, and a graphical interface. The standard
     components of modern graphical user interfaces, such as windows,
     icons, and the mouse, were pioneered at Xerox PARC.
     
     The Smalltalk language itself was the first 'true' object-oriented
     language in that it dealt exclusively with objects. All subsequent
     object-oriented languages have been based on the concepts used in
     Smalltalk. Smalltalk was important, not just for its language, but for
     the development tools available in the Smalltalk environment. These
     include class browsers and object inspectors. A class browser is a
     very powerful tool which allows program code to be edited in a much
     more convenient and structured way than with conventional editors.
     Because of the inherently well-defined structure of object-oriented
     programs, the class browser is capable of displaying a given program's
     class hierarchy in graphical form, allowing the user to 'point and
     shoot' to select a particular method (procedure) to be edited. Many
     programming tasks become menu driven, such as the creation of new
     classes, modifying the structure of the inheritance tree, and
     modifying the structure of a class. These operations are more complex
     and tedious when performed in a traditional editing environment.
     
     Tools such as these are an integral part of the promise of object
     oriented technology. They can simplify a programmer's life, reducing
     development time and costs. Although they are a rarity in the DOS
     world at present, as the move toward object-oriented technology grows,
     they will become more commonplace.

1.4. What is an object?
     
     One of the fundamental reasons that object orientation is enjoying
     such success as a programming paradigm is very simple: the real world
     is made up of objects. An invoice is an object. A stock item is an
     object. A balance sheet is an object. An entire company is an object.
     Objects can contain other objects; and in this way complete systems
     can be constructed using objects.
     
     But what is an object from a programming point of view? Simply put, it
     is a collection of related data, which is associated with the
     procedures which can operate on that data.
     
     By this definition, most well-structured programs could be said to
     contain objects. This is another contributing factor to the confusion
     surrounding the definition of object orientation.
     
     It is in fact possible to write programs in an object-oriented way in
     many traditional procedure-oriented languages. However, without the
     support provided by an object orientated languages, many compromises
     have to be made.
     
     An object-oriented languages formalizes the relationship of the data
     within an object to the program code which can operate on that data,
     by requiring that the compiler or interpreter be informed which
     procedures are allowed to operate on an object's data.
     
     Before we can clarify our definition of an object further, we need to
     explore a few other concepts.

1.5. Classes, instances and instance variables
     
     In any given system, many objects will exist. Many of these objects
     will be very similar to each other: for example, you might have
     thousands of invoice objects stored on disk. Although each one is
     different, they all share a common set of attributes. The same
     operations are valid on all of them. There is a term to describe such
     a collection of similar objects: it is called a class.
     
     A class can be thought of as a template, or specification, for
     creating an object. The class itself consists of details specifying
     what the structure of its objects should be. The class can also be
     said to 'contain' the program procedures which are permitted to
     operate on objects of that class.
     
     For example, an invoice class would contain procedures for printing
     and updating invoices. It would also contain details of the structure
     of an invoice object, for example that each invoice object must
     contain variables named 'date', 'customer', 'amount', etc.
     
     To look at it another way, we can define an object as an instance of a
     class. A given class may have many instances of itself (objects) in
     existence at any one time. Each of these instances has a structure
     determined by the class to which it belongs, but they are
     distinguished from each other by the data within that structure, which
     is stored in instance variables. The term instance variable
     distinguishes a variable that belongs to an object class from the
     ordinary stand-alone variables that we are used to. Instance variables
     are contained within objects, and are not directly accessible outside
     of those objects, although they can be accessed by sending messages to
     their objects.

1.6. Messages and methods
     
     Earlier, an object was defined as a module containing both procedures
     and data. An object's procedures are known as methods. This
     terminology helps to distinguish them from procedures which are not
     associated with an object, since there are fundamental differences. In
     a fully object-oriented system such as Smalltalk, there are no
     procedures, only methods. In a hybrid system such as C++, or Clipper
     with Class(y), both methods and procedures can coexist.
     
     Methods are not called in the same way that procedures are. Rather,
     messages are sent to objects, which respond by executing the
     appropriate method. All valid operations on or using the data in an
     object are defined by its methods, so all operations on an object are
     accomplished by sending messages to the object. Because of this, it is
     not necessary for other objects to access, or even know about, the
     internals of foreign objects. Objects behave like black boxes: send
     them a message, and they respond by executing the appropriate method.
     Send the 'print' message to an invoice object, and it will respond by
     printing itself. This black box approach is known generally as
     encapsulation, and while it is possible to achieve in procedural
     systems, object-oriented systems actively encourage, support and
     enforce it.

1.7. Inheritance - superclasses and subclasses
     
     Common properties among groups of classes can often be combined to
     form a parent class, or superclass. For example, it might make sense
     for a Quotation class, an Order class, and an Invoice class to all
     share the same superclass, a Sales Document class. The Quotation,
     Order, and Invoice classes are thus subclasses of the Sales Document
     class. This is known as inheritance. The subclasses inherit all the
     properties of their superclass, and may add unique, individual
     properties of their own. This concept can be extended further, with
     subclasses of subclasses. Such class hierarchies are a common feature
     of object-oriented systems.
     
     Inheritance is one of the most powerful features of object-oriented
     programming, since it allows reuse of existing code in new situations
     without modification. When a subclass is derived from a superclass,
     only the differences in behavior need to be programmed into the
     subclass. The superclass remains intact and will usually continue to
     be used as is in other parts of the system, while other subclasses are
     using it in different ways.

1.8. Polymorphism
     
     The term polymorphism in this context refers to the fact that the same
     message, such as 'print', can result in different behaviors when sent
     to different objects. Sending the 'print' message to a graph object
     has a different effect than it would on a balance sheet object. With a
     traditional procedural approach, the programmer is forced to
     differentiate procedure names, using names like 'PrnBalSheet' and
     'PrintGraph'. In an object-oriented language, this differentiation is
     unnecessary, and in fact unwise.
     
     Polymorphism has benefits for the programmer in that the same name can
     be used for conceptually similar operations in different classes, but
     its implications go deeper than that. It means that a message can be
     sent to an object whose class is not known. In a procedural system,
     given a variable of unknown type, a 'CASE' statement would typically
     be required to test the type of the variable and pass it to the
     correct procedure for the desired operation. In an object-oriented
     system, a message is sent to the object with no testing, and the
     object responds accordingly.
     
     This has important implications for inheritance, since it means that
     methods belonging to classes near the root of the inheritance tree do
     not need to know details of the subclasses which may be inherited from
     them. By sending messages with standardized names to the objects with
     which it deals, generic methods can be written which can later be used
     with any class which supports the required messages.



                                2. USING CLASS(Y)

2.1. Introduction
     
     The concepts described in the previous chapter should become clearer
     when applied in an actual program. To this end, we will now follow the
     process of creating a simple, real life class; and at the same time
     familiarizing ourselves with Class(y), enabling us to move on to a
     more complex example in the next section.
     
     First, some detail about Class(y). It consists of a library,
     CLASSY.LIB, and a header file, CLASS(Y).CH. Object-oriented Clipper
     5.01 programs can be written and compiled in conjunction with the
     header file, then linked with the library.
     
     Class(y) makes use of, and extends, Clipper 5.01's limited built-in
     object-oriented capabilities, specifically the send operator, or
     colon. In Clipper 5.01, a message is sent to an object as follows:
         
         object:message( <parameters,...> )
     
     Class(y) does not change this syntax. In fact, program modules which
     use objects, without defining classes themselves, can be compiled
     without any special header file, since they are standard Clipper 5.01
     programs in all respects.
     
     The include file, CLASS(Y).CH, must be included (using #include) when
     defining a new object class. A user-defined class is usually defined
     in a separate program module. It can then be compiled into an object
     module (.OBJ), and linked into an executable file, or added to a
     library file (.LIB).
     
     The use of the preprocessor and user-defined commands for class
     creation means that if and when Computer Associates release a version
     of Clipper with the ability to create user-defined classes, it should
     only be necessary to change the Class(y) header file, rather than any
     of the code implementing specific user-defined classes.
     
     Using Class(y), it is possible to mix and match programming styles. On
     the one hand, object classes can be developed and used in normal
     procedural programs, in the same way that the built-in TBrowse and Get
     classes are used in Clipper 5.01.
     
     At the other extreme, complete object-oriented systems can be
     developed, in which no stand alone procedures exist, other than a
     startup procedure. The startup procedure initializes the system and
     from then on, all program execution is effected by passing messages
     between objects.
     
     Any desired mix of these two approaches may be used, allowing
     developers to gradually familiarize themselves with the benefits of
     object-oriented programming.

2.2. Creating a class
     
     Perhaps the most fundamental feature required of an object-oriented
     programming language is the ability to create new object classes. With
     Class(y), a class consists of a class specification, which describes
     the overall structure of a class, and the class implementation, which
     contains the actual code for the methods of that class. These two
     components usually appear in the same module (.PRG file).

2.3. The class specification
     
     We will use the creation of a simple rectangle class as our first
     example. This class will consist of little more than the coordinates
     of the rectangle, along with a method to set these coordinates. Here
     is the class specification:
         
         // rectangle.prg
         
         #include "class(y).ch"
         
         CREATE CLASS Rectangle
              VAR top, left
              VAR bottom, right
         EXPORT:
              METHOD init
              METHOD set
              METHOD width, height
              METHOD area
         END CLASS
     
     This code is used by Class(y) to create the specified class. It is
     actually a type of function, which is usually called whenever
     instances of the class need to be created. It should be placed at the
     beginning of the module (.PRG file) in which the code (methods) for
     the class are defined.
     
     The first statement, CREATE CLASS, ;is straightforward. We are
     creating a class called Rectangle. All following statements up to the
     END CLASS statement are Class(y) class declaration statements, the
     purpose of which is to declare the structure of a class.
     
     VAR is one such statement. It is followed by one or more instance
     variable names. In this example, we are saying that the Rectangle
     class contains four instance variables: 'top', 'left', 'bottom' and
     'right'.
     
     Following the VAR statements is the EXPORT: statement.  This statement
     causes any methods and variables defined after this statement to be
     made accessible to any user of this class. By default, methods and
     variables are local to the class, and can only be accessed from the
     methods of that class. This is how encapsulation is enforced in
     Class(y).
     
     The METHOD command is used to  declare the names of the methods
     defined in this class. It is followed by one or more method names. In
     class Rectangle, we are declaring that five methods will be defined:
     'init', 'set', 'width', 'height' and 'area'.

2.4. Using the class
     
     Before we cover the actual definition of the methods, we will look at
     how the class might be used.
         
         // testrect.prg
         
         LOCAL x := Rectangle():new(5, 10, 15, 40)
         
         ? 'The dimensions of Rectangle x are as follows:'
         ? '      width:', x:width
         ? '     height:', x:height
         ? '       area:', x:area
         ? '        top:', x:top
         ? '       left:', x:left
         ? '     bottom:', x:bottom
         ? '      right:', x:right
         
         // eof testrect.prg
     
     This program creates a new instance of the class Rectangle and assigns
     it to the local variable 'x'. The expression:
         
         Rectangle():new( 5, 10, 15, 40 )
     
     can be understood as sending the 'new()' message to the Rectangle
     class, which has the effect of creating an instance of the Rectangle
     class with the specified dimensions.
     
     Terminology note: The 'Rectangle()' function in the above example is
     referred to as a class function, since it returns an object (a class
     object) which refers to the entire Rectangle class, rather than to a
     single instance of Rectangle.
     
     The method named 'new' is a predefined system method which creates a
     new object and initializes it. The 'new' method is a predefined system
     method. It causes the appropriate initialization to be performed by
     sending an 'init()' message to the newly created object, along with
     the parameters originally received by the 'new' method. Each class
     should have its own, specialized 'init' method. The job of the 'init'
     method is to initialize the new object according to the specified
     parameters.
     
     More terminology: The 'new' method, which is responsible for creating
     and initializing new objects, is known as a constructor method. The
     'init' method, which 'new' uses to initialize new objects, is known as
     an initializer method.
     
     Once we have created our object, we can use it just as we would any
     other Clipper 5.01 object, by sending it messages. The statement
     'x:width', for example, sends the 'width' message to the Rectangle
     'x'. In this particular case, this has the effect of invoking the
     'width' method, which calculates and returns a result.
     
     Running this program produces output similar to the following:
         
         C:\>testrect
         
         The dimensions of Rectangle x are as follows:
              width:         31
              height:        11
              area:         341
         Error CLASS(Y)/41  Scope violation (private): RECTANGLE:TOP
         Called from obj:TOP(0)
         Called from TESTRECT(10)
         C:\>
     
     Uh-oh! We have an error. Looking at line 10 of TESTRECT.PRG, we see
     that we have tried to print the value of 'x:top'. What is wrong with
     that?  Looking back to the specification of class Rectangle, we notice
     that the instance variable 'top' is declared before the EXPORT:
     statement. Because of this, 'top' is considered a hidden instance
     variable, which means it can only be accessed by methods belonging to
     class Rectangle. Our program, TESTRECT.PRG, is not a Rectangle method,
     and so is prevented from accessing this variable.
     
     Hidden instance variables are one of the fundamental benefits of
     object-oriented programming. A hidden instance variable is only
     accessible within the methods of its class. By making an instance
     variable hidden, we ensure that only a relatively small set of
     routines (the methods of that class) can change the variable. If the
     variable's value is incorrect, we know exactly which routines to
     examine.
     
     In a well-designed object-oriented system, it is often desirable to
     prevent the values of instance variables from being changed outside of
     their class. However, it is often necessary to access (but not change)
     an instance variable's value outside of the class. To facilitate this,
     instance variables can be declared as non-assignable, or read-only,
     using the keyword READONLY in the VAR command. Let's redefine the
     Rectangle class to allow external routines to read our instance
     variables:
         
         CREATE CLASS Rectangle
         EXPORT:
              VAR top, left       READONLY
              VAR bottom, right   READONLY
         
              METHOD init
              METHOD set
              METHOD width, height
              METHOD area
         END CLASS
     
     Notice that we have placed the instance variable declarations after
     the EXPORT: statement. This makes them accessible to any program, but
     the READONLY  clause in the VAR  command prevents other programs from
     assigning to these variables, in other words changing their value.
     Naturally, the methods of class Rectangle can still assign values to
     these variables - otherwise they would be useless.
     
     Running TESTRECT now gives us the results we expect:
     
         C:\>testrect
     
         The dimensions of Rectangle x are as follows:
          width:         31
          height:        11
          area:          341
          top:      5
          left:          10
          bottom:        15
         
              right:         40
         C:\>

2.5. Method Definitions
     
     The method definitions for a class consist of program code for all the
     methods specified for that class. This code is usually placed after
     the class specification, in the same module (.PRG file).
     
     When writing methods, you need to be aware of how a method differs
     from a normal function or procedure. A method, unlike a normal
     function or procedure, is not called directly, but rather is invoked
     as the result of a message sent to an object. A method cannot be
     invoked without an object being associated with it. A method acts on
     the object receiving the message; but to do so, it needs to be able to
     access it. To this end, a local variable called 'self' exists in all
     methods. 'self' refers to the object which received the message that
     is being acted on. Instance variables and methods belonging to that
     object are accessed via the 'self' variable. In the 'set' method in
     the code below, for example, the line:
         
         self:top := nTop
     
     assigns the value of the parameter 'nTop' to the instance variable
     'top' of the rectangle receiving the 'set()' message.
     
     Note: the names of parameters and the names of the corresponding
     instance variables in this example have purposely been made different.
     Although the statement 'self:top := top' would work correctly - since
     there is currently no ambiguity between instance variable names and
     ordinary Clipper variable names - in future versions of Clipper, this
     may change.
     
     Here are the method definitions for class Rectangle:
     
         // rectangle.prg continued...

         METHOD init( top, left, bottom, right ), ()
              self:set( top, left, bottom, right )
         RETURN self

         METHOD set( nTop, nLeft, nBottom, nRight )
              IF top <> NIL
                  self:top := nTop
              END
              IF left <> NIL
                  self:left := nLeft
              END
              IF bottom <> NIL
                  self:bottom := nBottom
              END
              IF right <> NIL
                  self:right := nRight
              END
         RETURN self
         
         METHOD width
         RETURN self:right - self:left + 1
         
         METHOD height
         RETURN self:bottom - self:top + 1
         
         METHOD area
         RETURN self:width * self:height
         
         // eof rectangle.prg
     
     The code is mostly self-explanatory. However, the METHOD command is
     being used differently from the way it was used inside the class
     specification.
     
     When used after a class specification, the METHOD command begins the
     definition of a method, just as the Clipper statements FUNCTION and
     PROCEDURE are used to begin the definition of a user-defined function
     or procedure.
     
     A method declared with the METHOD command must return a value, just
     like a function.  If you need to declare a method which does not
     return a value, you can use the METHOD PROCEDURE command.
     
     Tip: It has become standard practice to return 'self' from methods
     which do not otherwise need to return a value. This allows message
     sends to be chained. For example, if our Rectangle class contained a
     message called 'draw()', we might write an expression such as:
     
         oRect:set(5,4,10,15):draw()
     
     which would set the coordinates for the Rectangle object referred to
     by 'oRect', then send the 'draw()' message to that object. This is
     only possible if the 'set()' method returns 'self.'
     
     The first method defined above, 'init', makes use of a special feature
     of the METHOD command. Let's take a look at it.
         
         METHOD init( top, left, bottom, right ), ()
     
     After the parameter list, there is a comma, followed by a pair of
     parentheses. It is actually a second parameter list, which in this
     case is empty. The reason for its existence will remain a mystery
     until the next section, when we discuss inheritance. For the moment,
     it is sufficient to know that you should always include this second
     parameter list when defining the 'init' method.
     
     As discussed in the previous section, new objects are usually created
     by sending the 'new()' message to a class object. For example, to
     create a new instance of the Rectangle class, we use code such as
     this:
         
         obj := Rectangle():new( 5, 10, 15, 70 )
     
     This statement sends the 'new()' message, with the specified
     parameters, to the Rectangle class. The 'new()' method responds by
     creating a new, empty Rectangle object, and sending the 'init()'
     message to it to initialize it. A reference to the newly created and
     initialized Rectangle object is returned, and in the code above is
     stored in the variable 'obj'.
     
     Whenever a new object is created, by sending a 'new()' message to a
     class, the initializer for that class is called. The initializer's job
     is to initialize the new object, and it can take parameters as
     necessary to facilitate this. By default, the initializer method for a
     class is called 'init'.
     
     A class does not have to have an initializer, but it is highly
     recommended. In some cases, a class will inherit its initializer from
     a parent class (inheritance is described in the next section).
     
     If an initializer is not defined for a particular class, and if it
     does not inherit an initializer from a parent class, that class will
     still accept the 'new()' message. Instead of returning a properly
     initialized object, though, it will return an empty object - an object
     with all its instance variables set to 'NIL'.  This is not usually
     very useful or desirable.
     
     Design Tip: Why is creating completely empty objects not desirable?
     One of the ways in which correctness can be ensured in object-oriented
     programs is by ensuring that objects are always in a valid state. An
     empty object is unlikely to be in a valid state. For example, a
     Rectangle object with its corner coordinates set to 'NIL' cannot be
     drawn and will not respond correctly to many messages. An object like
     this is in an invalid state.
     
     Now that we have finished with RECTANGLE.PRG, we have the makings of a
     complete system and can actually test it. The system can be compiled
     as follows:
         
         clipper rectangle /n/w/a/b
         clipper testrect    /w/a/b
         rtlink fi testrect, rectangle lib classy
     
     This should create the file TESTRECT.EXE which can then be run. Note
     that the /b switch is used, to include debug information. It might be
     instructive to trace through the program in the debugger (CLD
     TESTRECT) to get a feel for what is happening.

2.6. Inheritance
     
     An object-oriented language is not complete if it does not support
     inheritance. Inheritance is the mechanism which allows existing code
     to be reused in different circumstances without modification.
     
     As an example, we will declare a class called ScreenRect which can
     draw a rectangle on the screen and manipulate it. Since we already
     have a rectangle class, we can save a lot of time by inheriting from
     that class.
     
     The code below defines the class ScreenRect. A new feature is
     introduced here: the double colon (::) is a shorthand notation for
     sending a message to the self object in a method. This is particularly
     useful in a statement such as the following, adapted from the 'hide'
     method below:
         
         restscreen(self:top, self:left, self:bottom, self:right, ;
                   self:screenBuf)
     
     With the double colon, this becomes:
         
         restscreen(::top, ::left, ::bottom, ::right, ::screenBuf)
     
     which might look strange at first, but it is easy to get used to and
     is easier to read than the alternative.
     
     Here is the code for the ScreenRect class:
         
         // scrnrect.prg
         
         #include "class(y).ch"
         #include "box.ch"
         
         CREATE CLASS ScreenRect FROM Rectangle
              VAR screenBuf
              VAR boxStyle
              VAR color
         
         EXPORT:
              METHOD init
              METHOD moveUp, moveDown
              METHOD moveLeft, moveRight
              METHOD hide, show
         END CLASS
         
         METHOD init( top, left, bottom, right, color, boxStyle ), ;
                   ( top, left, bottom, right )
         
              ::boxStyle := IF(boxStyle == nil, B_DOUBLE, boxStyle)
              ::color := color
              ::show()
         RETURN self
         
         METHOD hide()
              restscreen(::top, ::left, ::bottom, ::right, ::screenBuf)
         RETURN self
         
         METHOD show()
              local oldColor := setcolor(::color)
              ::screenBuf := savescreen(::top, ::left, ::bottom, ::right)
              @ ::top, ::left, ::bottom, ::right box ::boxStyle
              setcolor(oldColor)
         RETURN self
         
         METHOD moveUp(n)
              ::hide()
              ::set(::top - n, nil, ::bottom - n, nil)
              ::show()
         RETURN self
         
         METHOD moveDown(n)
              ::hide()
              ::set(::top + n, nil, ::bottom + n, nil)
              ::show()
         RETURN self
         
         METHOD moveLeft(n)
              ::hide()
              ::set(nil, ::left - n, nil, ::right - n)
              ::show()
         RETURN self
         
         METHOD moveRight(n)
              ::hide()
              ::set(nil, ::left + n, nil, ::right + n)
              ::show()
         RETURN self
         
         // eof scrnrect.prg
     
     A number of new techniques have been sneaked in above. First and most
     important is inheritance. The ScreenRect class has been declared by
     inheriting from the Rectangle class, using the statement:
         
         CREATE CLASS ScreenRect FROM Rectangle
     
     This means that the ScreenRect class inherits all of the instance
     variables and methods of the Rectangle class, in addition to its own
     instance variables and methods. In the 'hide' method, for example, the
     instance variables 'top', 'left', 'bottom', and 'right', which are
     Rectangle instance variables, have been accessed, along with
     'screenBuf', which is a ScreenRect instance variable.
     
     Inheriting from another class raises an issue with regard to the
     initializer method 'init': the instance variables of the parent class,
     or superclass, should also be initialized when a new ScreenRect object
     is created. Since the superclass would usually have its own
     initializer for this purpose, it makes sense to use it - after all,
     one of the benefits of object-oriented programming is supposed to be
     reusability. Class(y) automates this process, by allowing the
     parameters to be passed to the superclass to be specified in the
     METHOD command. In the above example, the line:
         
         METHOD init( top, left, bottom, right, color, boxStyle ), ;
                   ( top, left, bottom, right )
     
     begins the definition of an initializer method which accepts the
     specified parameters. Because of the second parameter list, its first
     operation is to call the initializer in the superclass with the
     parameters specified in the second list. The second parameter list
     must, of course, match what is expected by the superclass initializer,
     in this case that of the class Rectangle.
     
     This 'init' method is typical of most initializers. It passes some of
     its parameters up to the initializer in its superclass to ensure that
     inherited variables are initialized, and then it initializes the
     instance variables belonging to the class in which it is defined.
     
     An interesting point here is that because the instance variables of
     class Rectangle were declared read-only, class ScreenRect would be
     prevented from directly setting these variables. The only way
     ScreenRect methods can affect these variables is by invoking the
     initializer in the Rectangle class, or using the 'set' method which
     was written for that purpose. Note that if the instance variables of
     class Rectangle had been declared after a PROTECTED: command, then
     they could be updated from the ScreenRect class, since it is a
     subclass, but could not be updated from other, unrelated classes.
     
     The following sample program will allow us to test the ScreenRect
     class:
     
         // testscrn.prg

         #include "class(y).ch"

         PROCEDURE main
            LOCAL i
            LOCAL rect1 := ScreenRect():new(5, 5, 10, 25, 'R+/G')
            // the following uses default colors:
            LOCAL rect2 := ScreenRect():new(15, 60, 22, 75)
            FOR i := 1 TO 10
                rect1:moveDown(1)
                rect1:moveRight(1)

                rect2:moveUp(1)
                rect2:moveLeft(1)
            NEXT
         RETURN
     
     Compile this program as follows:
         
         clipper testscrn   /w/a/b
         clipper scrnrect /n/w/a/b
         rtlink fi testscrn, scrnrect, rectangle lib classy
     
     Note that the RECTANGLE module has been linked in above. Since the
     ScreenRect class is inherited from the Rectangle class, the RECTANGLE
     module is required when linking. If it is omitted, a link error will
     occur referring to an undefined symbol RECTANGLE.
     
     You can now run TESTSCRN.EXE. Again, tracing through it in the
     debugger is a useful exercise (CLD TESTSCRN).

2.7. Class variables & methods
     
     One other fairly important concept needs to be introduced: class
     variables and methods. Up until now, we have talked about instance
     variables, and the methods we have referred to are, in a sense,
     instance methods in that they deal with instances of the class and are
     invoked by sending messages to such instances.
     
     Every object, or instance of a class, has its own set of instance
     variables with its own unique values, which differentiate it from
     other members of the same class. Similarly, every method has implicit
     access to the object 'self', which is the specific object, or
     instance, that the method is operating on.
     
     There are some situations, however, where all instances of a class
     need to share the same data, or where a method needs to take action
     which affects the class as a whole. Class variables and class methods
     exist to cater for these situations.
     
     A class variable is a variable, defined in the class specification,
     which is shared among all instances (objects) of its class. Where
     instance variables can have a different value in each instance of a
     class, only one copy of a class variable exists for an entire class.
     
     Similarly, a class method is a method which applies to an entire
     class, in that it can only be invoked by sending a message to a class
     object, and its 'self' variable will then refer to that class object.
     Because of this, a class method cannot directly access (via 'self')
     the instance variables defined in its class, but it can access its
     class variables.
     
     For example, if we were to expand our ScreenRect class into a more
     complete windowing system, one of the features we might want is a
     method that would close all windows on the screen. To implement this,
     we would need a class method, perhaps called 'hideAll'. It should be a
     class method since it relates to all existing instances of the class,
     not just a single instance. To do its job, 'hideAll' would need access
     to all of the instances in existence at a given time. To achieve this,
     we could define a class variable that contains an array of all
     existing ScreenRect objects. We will call this variable 'activeRects'.
     
     To implement this, we might modify our class specification as follows:
         
         CREATE CLASS ScreenRect FROM Rectangle
              VAR  screenBuf
              VAR  boxStyle
              VAR  color
         
              CLASS VAR activeRects
         
         EXPORT:
              METHOD    init
              METHOD    moveUp, moveDown
              METHOD    moveLeft, moveRight
              METHOD    hide, show
         
              CLASS METHOD   hideAll
              CLASS METHOD   initClass
         
         END CLASS
     
     The class variable 'activeRects' was declared using the CLASS VAR
     command. Notice that it was declared before the EXPORT: command,
     making it a hidden variable. There is no need for other modules to
     have direct access to this variable, and making it hidden prevents an
     external routine from mistakenly setting the variable to 'NIL', for
     example, thereby destroying our list of active objects!
     
     Two class methods were declared using the CLASS METHOD command:
     'hideAll' and 'initClass'. The 'hideAll' method is the one we're
     trying to define; but where did 'initClass' come from? It is there for
     the sole purpose of initializing any class variables. Only one copy of
     each class variable is shared by all instances of a class, so
     initializing these variables in the 'init' method doesn't make sense,
     since the class variables would get reinitialized every time an object
     was created. We could put in an 'IF' statement to check whether the
     class variables had already been initialized, but this would be a
     workaround at best. The 'initClass' method is intended to take care of
     this issue. If a class has a method called 'initClass', Class(y) will
     automatically invoke that method only once, when the class is first
     created. This makes the 'initClass' method an ideal place to
     initialize class variables. Note that 'initClass' must be declared as
     a 'CLASS METHOD'.
     
     Here are the method definitions for 'initClass' and 'hideAll' as they
     appear in SCRNRECT.PRG:
         
         METHOD initClass
              ::activeRects := {}
         RETURN self
         
         METHOD hideAll
              LOCAL i
              FOR i := 1 TO LEN(::activeRects)
                   ::activeRects[i]:hide
              NEXT i
         RETURN self
     
     For this to work correctly, we will need to make sure that the
     'activeRects' variable is maintained correctly, by adding the
     following code somewhere inside the ScreenRect initializer:
         
         AADD( ::activeRects, self )
     
     This will add each new ScreenRect object, as it is created, to the
     ::activeRects array.
     
     Finally, we should also ensure that ScreenRect objects get removed
     from the active list when they are no longer active, in other words
     when 'hide()' is invoked. We can do this using something of a
     sledgehammer approach, by adding the following code to the 'hide'
     method:
     
        FOR i := 1 TO LEN( ::activeRects )
            IF ::activeRects[i] == self
                ADEL( ::activeRects, i )
                ASIZE( ::activeRects, LEN( ::activeRects ) - 1 )
            END
        NEXT i
     
     This is somewhat inefficient, in that it has to scan the array of
     active rectangles to find 'self', i.e. the one that has received the
     'hide' message. A better implementation might be to enforce a stack-
     based approach, so that only the most recently displayed ScreenRect
     can be hidden. This would also prevent problem of restoring screen
     areas in the wrong sequence. In fact, the sample Window class supplied
     with Class(y) uses a List class to achieve something very similar.



                           3. PULL-DOWN MENU TUTORIAL

3.1. Introduction
     
     Having covered some of the basics of creating a class and using
     inheritance, we'll move on to a more sophisticated example. The
     program we are going to discuss implements a general pull-down menu
     system. It has been kept fairly simple to serve as a clear
     illustration of OOP techniques.
     
     Consider a typical pull-down menu:
         
             File      Window      Block
      
      Load
      Edit
      Save
       
       Document
       Text
     
     Figure 1
     
     We will examine the operation of a menu like this in some detail, to
     give us a specification to work from.
     
     A pull-down menu system consists of a number of components, the first
     of which is the menu bar, running horizontally across the screen,
     containing a number of options. This menu behaves like a normal
     Clipper menu, allowing options to be highlighted with a light bar
     controlled by the cursor keys, or by typing the first letter of the
     desired option. When an option is selected by pressing the ENTER key,
     an action associated with that option is performed. In most cases,
     this action will be to display a corresponding menu, 'pulled down'
     from the menu bar. In the example above, the 'File' option has been
     selected, which has resulted in the 'Load/Edit/Save' menu being pulled
     down. The pulled-down menu also behaves like a standard Clipper menu,
     separate from the menu bar. Because the menu's options are arranged
     vertically, the up and down arrows are used to move between options.
     Pressing a left or right arrow results in the pulled-down menu being
     closed, and its sibling to the left or right being pulled down
     instead. Finally, selecting an option from this menu again results in
     an action being executed. Sometimes, this action will consist of yet
     another menu - but when this happens, the new menu will not behave
     like a pull-down menu. Aside from not being pulled down from the menu
     bar, it would have no siblings and so the left and right arrow keys
     cannot select other menus. We will refer to this kind of menu as a pop-
     up menu. In the above example, the 'Save' option has been selected
     from the pull-down menu, resulting in a pop-up menu containing the
     options 'Document' and 'Text'.

3.2. Designing the classes
     
     Now, to write an object-oriented program to implement this menu
     system, a good first step is to decide on the classes which will make
     up the system. From the specification, we can see that we are dealing
     with three varieties of menu: the menu bar, the pull-down menu, and
     the pop-up menu. It would make sense to have a class for each one of
     these menu types. However, the different types of menu have many
     common characteristics. To avoid duplicating code, we need a class
     which has the characteristics common to all three types of menu. We
     will call this class BaseMenu.
     
     A class such as BaseMenu is often referred to as an abstract class,
     since you would not normally create instances of that class. Instead,
     you would create instances of the three real menu classes (which we
     shall call MenuBar, PullDnMenu, and PopupMenu), which will all be
     inherited from the BaseMenu class. This means that all three menu
     varieties will have the same basic set of instance variables and
     methods, derived from BaseMenu. In addition, each of the classes may
     implement new methods and variables of their own.
     
     The most important data which the BaseMenu class will contain are the
     details of the menu items themselves. But what constitutes a menu
     item? It must include option's label text, which is displayed on the
     menu, and an action associated with that option. We might also want to
     store the row and column at which the label should be displayed. With
     all these related attributes, it is worth creating a MenuItem class to
     group all of this information together.
     
     So the BaseMenu class will contain an array of MenuItem objects. This
     array will be referred to by an instance variable called 'items'.

     Figure 2  Pulldown menu program class diagram

    Ŀ
     class:      BaseMenu         
    Ĵ
     instance                            Ŀ
     variables:  items ----------------> class:      MenuItem         
                 currPos                 Ĵ
                 parent                   instance                     
    Ĵ        variables:  row              
     methods:    addItem                              col              
                 draw                                 label            
                 setKeys     (*)                      action           
                 clearKeys   (*)                      isActive         
                 newMenuPos              Ĵ
                 exec                     methods:    draw             
                        exec             
                                                      nextCol          
                                                      nextRow          
                                         
                    
                    ͻ
                                                       
    Ŀ       Ŀ
     class:      MenuBar                  class:      PopupMenu        
    Ĵ       Ĵ
     instance                             instance                     
     variables:                           variables:  window           
    Ĵ                    width            
     methods:    draw                    Ĵ
                 addItem                  methods:    draw             
                 newMenuPos                           menuTop          
                        menuLeft         
                                                        addItem          
                                                        exec             
                                           
                                                        
                                                        
                                           Ŀ
                                            class:      PullDnMenu       
                                           Ĵ
                                            instance                     
                                            variables:                   
                                           Ĵ
                                            methods:    menuTop          
                                                        menuLeft         
                                                        setKeys          
                                                        clearKeys        
                                                        moveLeft         
                                                        moveRight                
                                           
     

3.3. Pull-down menu program class diagram
     
     A diagram of the class hierarchy for our pull-down menu system is
     shown in Figure 2. Please note that this diagram does not completely
     conform to any standard diagramming methodology. Nevertheless, it
     serves to illustrate our example, and it shows how easily an object
     oriented design can be meaningfully diagrammed.
     
     Each class is represented by its own box. Inside the box are listed
     the name of the class, its instance variables, and methods. By
     convention, solid arrows between the classes point from a subclass to
     its superclass. The dotted arrow pointing from the instance variable
     'items' in the BaseMenu class has an arrow pointing to the MenuItem
     class, indicating that the 'items' variable in a BaseMenu object will
     contain MenuItem objects.
     
     The diagram shows that the MenuBar and PopupMenu classes have been
     inherited from BaseMenu, as described earlier. However, PullDnMenu has
     not been inherited directly from BaseMenu. The reason for this is that
     a PullDnMenu is very similar to a PopupMenu. A PullDnMenu does all of
     the things which a PopupMenu does, such as drawing a window on the
     screen. However, according to our specification, it has one extra
     behavior which PopupMenu doesn't have: it responds to the left and
     right arrow keys by activating the appropriate sibling menu on the
     menu bar. To avoid duplicating code, PullDnMenu has been inherited
     from PopupMenu. This means that PullDnMenu only needs to implement the
     code necessary for its extra, unique behavior; it inherits all its
     other behavior from PopupMenu in the form of methods and instance
     variables.
     
     Generally speaking, in an inheritance tree (which usually has a root
     at the top, and branches out downwards), the classes nearer the root
     are always the most general classes. As you move away from the root,
     the classes should become more and more specialized, only implementing
     the extra features required, without needing to reimplement features
     that already exist further up the tree.

3.4. Explanation of the code
     
     When going through the code for the pull-down menu system, don't be
     overly concerned if it does not make perfect sense at first. The
     program has been designed to illustrate many of the most important
     concepts in OOP in general, using a system consisting only of
     interacting classes.
     
     You may notice that the program makes use of a Window class, which is
     included with Class(y). We do not cover the operation of this class in
     detail, since it is incidental to the overall structure of the
     program. In brief, the Window class allows windows to be created,
     popped up and popped down, handling screen saving and the related
     functions transparently. Screen I/O within a window is relative to the
     window's borders, so when a window is active, an @ 0, 0 SAY... command
     will refer to the top left corner of that window.

3.4.1. Creating a class - MenuItem
     
     We will start with the MenuItem class, which is a stand-alone class,
     and hence quite straightforward. The source code for this is contained
     in the file MENUITEM.PRG on the distribution disk. As mentioned
     earlier, it contains instance variables for 'row', 'column', 'label',
     and 'action'. It also has a flag, 'isActive', which can be used to
     deactivate a particular option.
     
     Here is the class specification:
     
         /*
             MenuItem.prg

             Copyright (c) 1991, 1992 Chris Muller and Anton van Straaten
         */

         #include "class(y).ch"
         #include "win.ch"   // Class(y) sample window library header file


         CREATE CLASS MenuItem
             VAR     label
             VAR     action
         
         EXPORT:
             VAR     row, col    READONLY
             VAR     isActive    READONLY
         
             METHOD  init
             METHOD  draw
             MESSAGE exec TO action
             METHOD  nextCol
             METHOD  nextRow
         END CLASS
         
         
         METHOD init( nRow, nCol, cLabel, oAction, isActive ), ()
             ::row      := nRow
             ::col      := nCol
             ::label    := cLabel
             ::action   := oAction
             ::isActive := IF( isActive == NIL, .T., isActive )
         RETURN self
         
         
         METHOD draw
             IF ::isActive
                 @ ::row, ::col PROMPT ::label
             ELSE
                 @ ::row, ::col SAY ::label
             END
         RETURN self
         
         
         METHOD nextRow
         RETURN ::row + 1
         
         
         METHOD nextCol
         RETURN ::col + LEN( ::label )
         
         // eof menuitem.prg
     
     Skipping through the code a bit, we can see the definition of one of
     the methods, 'draw':
         
         METHOD draw
             IF ::isActive
                 @ ::row, ::col PROMPT ::label
             ELSE
                 @ ::row, ::col SAY ::label
             END
         RETURN self
     
     We have already discussed the role of the 'self' object within
     methods, but this is a good opportunity to look at how it works in a
     real method. Remember that the double colon (::) is shorthand for
     sending a message to the 'self' object.
     
     When a statement like 'item:draw()' is executed, if the 'item'
     variable refers to an object of class MenuItem, then the 'draw' method
     in that class will be invoked. Within this method, 'self' is
     automatically set to refer to the same MenuItem object referred to by
     the caller's 'item' variable - the variable which the 'draw' message
     was sent to. The statement above, then, will cause that MenuItem's
     label to display in the correct row and column, which is also stored
     in the MenuItem object.
     
     The initializer for the MenuItem class is quite straightforward. It
     accepts up to five parameters specifying the position, text, action
     and status of the MenuItem, and assigns these parameters to its
     instance variables. The initializer will be invoked automatically when
     a new MenuItem object is created, as in the following statement:
         
         LOCAL item := MenuItem():new( 1, 1, "Print", { || Print() } )
     
     This would create a new MenuItem object containing the specified
     values, and set the 'item' variable to refer to this object.
     
     If you trace through this code in the Clipper debugger, you will see
     the class functions, such as MenuItem, being called every time a new
     object is created. The first time such a function is called, every
     line will be executed, since the class is being created; on subsequent
     occasions, it returns immediately, passing a reference to the class
     back to the caller.

3.4.2. Other MenuItem methods
     
     Only two other methods are defined in the MenuItem class: 'nextrow'
     and 'nextcol'. They are used to calculate the next available row or
     column after the current option. They are invoked by the 'addItem'
     method in the PopupMenu and MenuBar classes respectively.
     
     There remains one unexplained declaration in the MenuItem class
     specification:
         
         MESSAGE exec TO action
     
     This statement makes use of the Class(y) feature known as delegation.
     The MESSAGE command in this context indicates that we are not defining
     a method for this message, but we are specifying what to do in
     response to the message. In this case, the 'TO action' clause
     specifies that when the 'exec' message is received by a MenuItem
     object, the message will be forwarded (delegated), with all
     parameters, to the object referred to by the 'action' instance
     variable. If we did not use this delegation feature, we would have to
     define a MenuItem method such as this:
         
         METHOD exec( oParent )
         RETURN ::action:exec( oParent )
     
     Using delegation saves code and improves performance. In this example,
     delegation is used to allow MenuItem objects to receive 'exec'
     messages and respond to them by executing the action associated with
     that item - by forwarding the 'exec' message to the object referred to
     by the 'action 'instance variable. The BaseMenu class implements an
     'exec' method which displays and executes a given menu, so if the
     object referred to by 'action' is a menu, the 'exec' message will have
     the desired effect. In this way, menus can be nested to any depth.
     
     At some point, though, we will want to perform an action other than
     displaying a menu. Many Clipper menu systems work by storing actions
     as code blocks, and evaluating the appropriate block when an option is
     selected. To cater for this, code blocks are treated as a special type
     of object, which can be evaluated by sending an 'exec' message to
     them. (Note: in Clipper 5.01, a similar but undocumented capability
     exists, allowing an 'eval' message to be sent to a code block.
     Class(y) supports both the 'exec' and 'eval' messages).
     
     So with Class(y), there is more than one way to evaluate a code block:
     
         LOCAL bSquare := { |x| x * x }
     
         ? eval(bSquare)               // the old way
         ? bSquare:eval()              // the (undocumented) 5.01 way
         ? bSquare:exec()              // the Class(y) way
         ? { |x| x + 2 }:exec()        // this also works!
     
     By implementing an 'exec' method in a given class, we can use that
     class with this menu system without any modification to the existing
     menu classes. For example, we might have a Dialog Box class, which on
     receiving an 'exec()' message would display itself and allow the
     appropriate user input. With a complete population of such classes
     (e.g. Report, Graph, Browse...), we would do away with code blocks
     (for this purpose) completely.

3.4.3. The BaseMenu class
     
     Much of the functionality of the menu system is encapsulated in the
     BaseMenu class (code in BASEMENU.PRG). However, different specific
     features are required by each of its subclasses. To support this, two
     messages are declared in the BaseMenu class, without corresponding
     methods, as follows:
         
         MESSAGE setKeys   IS DEFERRED
         MESSAGE clearKeys IS DEFERRED
     
     As with 'exec' in MenuItem, the MESSAGE command is used to declare
     messages which have no corresponding method defined in the current
     class. The clause IS DEFERRED causes the messages to invoke a method
     called 'deferred' which is defined in the system class, Object. All
     the deferred method does is to generate an error as follows:
         
         Message should be implemented by subclass
     
     What this does is force subclasses to redefine these messages. If they
     do not, the above error will occur. Deferred methods are often used in
     abstract classes such as BaseMenu. They document that the specified
     message must be overridden in a subclass, and they ensure that if the
     message is not overridden, a meaningful error will occur.
     
     In this menu system, only the PullDnMenu class has any need to
     implement implement these methods. For the other subclasses of
     BaseMenu (PopupMenu and MenuBar), no action needs to be taken in
     response to the 'setKey' and 'clearKey' messages, so the following
     declarations are used in those classes:
         
         MESSAGE setKeys   IS NULL
         MESSAGE clearKeys IS NULL
     
     Here, the IS clause of the MESSAGE command is used to map the message
     to the 'null' method, which like 'deferred' is defined in the system
     class, Object. The IS clause can be used to cause any method defined
     in a superclass to be invoked in response to the specified message.
     The Object class is the ultimate superclass of all classes in
     Class(y), and it defines methods such as 'deferred' and 'null' for
     exactly this purpose.
     
     As discussed earlier, BaseMenu contains an array of MenuItem objects
     stored in an instance variable called 'items'. If you look at the
     'draw' method in BASEMENU.PRG, you will see that it is quite simple,
     just looping through the item array and sending a 'draw()' message to
     each item in turn. This has the effect of displaying all the options
     for a particular menu on the screen. Note that it does not draw a box
     around the items; this additional specialized behavior is implemented
     by the subclasses PopupMenu and MenuBar, since the one draws a box, or
     window, while the other merely draws a bar across the screen.
     
     The BaseMenu initializer takes an array of item/action pairs and
     initializes the 'items' instance variable by invoking the addItem
     method for each item pair. The addItem method creates a new instance
     of MenuItem and adds this to the 'items' array.
     
     The 'exec' method in BaseMenu causes the menu to be displayed on the
     screen, using the draw method, and executes a MENU TO command to allow
     the user to choose an option. If an option is selected, the 'exec'
     method is sent to that MenuItem object, causing the appropriate action
     to take place.
     
     The 'newMenuPos' method is invoked by the various classes on their
     parent menu to establish where on the screen to draw themselves.
     
         /*
             BaseMenu.prg

             Copyright (c) 1991, 1992 Chris Muller and Anton van Straaten
         */

         #include "class(y).ch"


         CREATE CLASS BaseMenu
         PROTECTED:
             VAR items
             VAR currPos
             VAR parent

         EXPORT:
             METHOD  init
             METHOD  addItem
             METHOD  draw

             METHOD  exec
             METHOD  newMenuPos

             // declaring the following two methods as deferred
             // will force subclasses to override them.
             MESSAGE setKeys     IS DEFERRED
             MESSAGE clearKeys   IS DEFERRED
         END CLASS


         METHOD init( aItems ), ()
             LOCAL i

             ::items   := {}
             ::currPos := 1

             IF aItems != NIL
                 FOR i := 1 TO LEN( aItems )
                     // note: following is a bit tricky; invokes addItem in
                     // in the subclass, which takes fewer parameters than
                     // BaseMenu's addItem.
                     ::addItem( aItems[i, 1], aItems[i, 2] )
                 NEXT
             END
         RETURN self


         METHOD draw()
             LOCAL i

             FOR i := 1 TO LEN( ::items )
                 ::items[i]:draw()
             NEXT i
         RETURN self


         METHOD addItem( nRow, nCol, cLabel, oAction, lActive )
             AADD( ::items, MenuItem():new( nRow, nCol, cLabel, ;
                                             oAction, lActive ) )
         RETURN self


         METHOD exec( oParent )
             LOCAL finished := .f.
         
             ::parent := oParent
         
             WHILE !finished
                 ::draw()
         
                 ::setKeys()
                 MENU TO ::currPos
                 ::clearKeys()
         
                 finished := ( ::currPos == 0 )
         
                 IF !finished
                     ::items[::currPos]:exec( self )
                 END
             END
         RETURN self
         
         
         METHOD newMenuPos
         RETURN ::currPos
         
         // eof basemenu.prg

3.4.4. The MenuBar class
     
     This class inherits all the behavior of BaseMenu. It adds no instance
     variables of its own. It adds a replacement 'draw' method, which
     highlights the bar across the top of the screen and then invokes the
     'draw' method in BaseMenu. This is done with the following statement:
         
         ::super:draw()      // equivalent to self:super:draw()
     
     Explicitly invoking a method in a superclass is a very common
     operation in OOP, and is typically used in exactly this situation - to
     add functionality to a method defined in a superclass. In Class(y),
     'super' is a reserved message which all classes accept (since it is
     defined in the Object class), and respond to by passing the next
     message received on to their superclass.
     
     The MenuBar class, having no instance variables of its own, does not
     need to perform any initialization of  its own. Accordingly, no 'init'
     method has been defined. However, MenuBar will inherit the 'init'
     method from the superclass, BaseMenu, ensuring that inherited instance
     variables are correctly initialized.
     
         /*
             MenuBar.PRG

             Copyright (c) 1991 Chris Muller and Anton van Straaten
         */

         #include "class(y).ch"

         #define OPTION_SPACING  4


         CREATE CLASS MenuBar FROM BaseMenu
         EXPORT:
             METHOD  draw
             METHOD  addItem
             METHOD  newMenuPos

             // we must override parent's DEFERRED messages, but this class
             // doesn't need to do anything with them, so map them to NULL.
             MESSAGE setKeys     IS NULL
             MESSAGE clearKeys   IS NULL
         END CLASS


         METHOD addItem( cLabel, oAction, isActive )
             LOCAL nCol

             // establish screen column for new option
             IF len(::items) == 0
                 nCol := OPTION_SPACING
             ELSE
                 nCol := ATAIL( ::items ):nextCol() + OPTION_SPACING
             END

             // invoke addItem in the superclass (BaseMenu)
             ::super:addItem( 0, nCol, cLabel, oAction, isActive )
         RETURN self
         
         
         METHOD draw()
             winCurrent(0)       // selects main screen
             @ 0, 0              // draw the bar
             ::super:draw()      // invoke superclass' draw method
         RETURN self
         
         
         METHOD newMenuPos
         // tells a child menu where to put itself
         RETURN ::items[::currPos]:col
         
         // eof menubar.prg

3.4.5. Overriding an inherited method
     
     For inheritance to be an effective mechanism for code reuse, we need a
     way of modifying behavior that has been inherited from a superclass,
     without modifying the superclass itself. This can be done by
     overriding methods that have been defined in a superclass.
     
     The newMenuPos method in MenuBar completely overrides the method of
     the same name in BaseMenu. Remember that 'newMenuPos' is invoked by a
     child menu and is used to determine where that menu should draw
     itself. When a MenuBar is the parent, the child menu must be drawn
     underneath the corresponding option on the bar, so 'newMenuPos'
     returns the relevant column position. The corresponding method in
     BaseMenu is used without change by the other two subclasses.
     
     The only other method in MenuBar is 'addItem', also a reimplementation
     of a BaseMenu method. This 'addItem' takes only three parameters: the
     'label' for the option, the 'action' object and the 'isActive' flag.
     It decides where to put the new item, using the 'nextCol' method in
     MenuItem. It then invokes addItem in the superclass with the
     additional row and column parameters. So in this case, although we
     have overridden the addItem method defined in the superclass, the
     overriding method still makes use of it; in this way, we add
     functionality rather than replacing it.
     
     Calculating the row and column like this means that the user of the
     MenuBar class does not have to worry about it. MenuBar's 'addItem'
     method becomes a simplified shell or interface to BaseMenu's 'addItem'
     method.

3.4.6. The PopupMenu class
     
     This class is similar in structure to MenuBar, since it is also
     inherited directly from BaseMenu. Like MenuBar, it refines the 'draw'
     and 'addItem' methods. In this case the refinements have to do with
     drawing a box, or window, around the menu. It adds two instance
     variables for this purpose, 'window' to refer to the window object and
     'width' which is used in its 'addItem' method to determine the
     window's required width. In addition, it has to redefine the 'exec'
     method, so that it can remove the window after execution is complete.
     
     Two other methods are defined: 'menuTop' and 'menuLeft'. These are
     needed to make the window drawing behavior more general, since
     PullDnMenu is inherited from PopupMenu and it has slightly different
     window drawing requirements. In PopupMenu, these methods return
     coordinates based on the parent menu's position, assuming that the
     parent menu is a PullDnMenu or another PopupMenu.
     
         /*
             PopupMenu.PRG

             Copyright (c) 1991, 1992 Chris Muller and Anton van Straaten
         */

         #include "class(y).ch"
         #include "win.ch"


         CREATE CLASS PopupMenu FROM BaseMenu
         PROTECTED:
             VAR     window
             VAR     width

             METHOD  menuTop, menuLeft

         EXPORT:
             METHOD  init
             METHOD  draw
             METHOD  addItem
             METHOD  exec

             // we must override parent's DEFERRED messages, but this class
             // doesn't need to do anything with them, so map them to NULL.
             MESSAGE setKeys     IS NULL

             MESSAGE clearKeys   IS NULL
         END CLASS


         /*
             init()

             The ::width variable must be initialized before the superclass'
             initializer is invoked, so we aren't use the extended METHOD
             syntax below.  Instead, the superclass' initializer
             is invoked explicitly with the statement ::super:init(...).
         */

         METHOD init( aItems )
             ::width := 0
             ::super:init( aItems )
         RETURN self


         METHOD draw()
             LOCAL bottom, right

             IF ::window == NIL
                 bottom := ::menuTop + len(::items) + 1
                 right  := ::menuLeft + ::width + 1
                 ::window := Window():new( ::menuTop, ::menuLeft, ;
                                           bottom, right, SNGLBORD )
             END
             ::super:draw()
         RETURN self


         METHOD menuTop
         RETURN winTop() + ::parent:newMenuPos()


         METHOD menuLeft
         RETURN winLeft() + 2


         METHOD addItem( cLabel, oAction, isActive )
             LOCAL nRow
         
             // establish screen row for new option
             IF LEN( ::items ) == 0
                 nRow := 0
             ELSE
                 nRow := ATAIL( ::items ):nextRow
             END
         
             ::super:addItem( nRow, 0, cLabel, oAction, isActive )
             ::width := MAX( ::width, LEN( cLabel ) )
         RETURN self
         
         
         METHOD exec( oParent )
             // invoke the exec method in the superclass (BaseMenu)
             ::super:exec( oParent )
             ::window:kill()
             ::window := NIL
         RETURN self
         
         // eof popupmen.prg

3.4.7. The PullDnMenu class
     
     PullDnMenu is inherited from PopupMenu, and adds no new instance
     variables of its own. It overrides the 'menuTop' and 'menuLeft'
     methods with its own, which return position values which assume that
     its parent menu is a MenuBar (since PullDnMenus are always pulled down
     from a menu bar).
     
     PullDnMenu also defines 'setKeys' and 'clearKeys', which you may
     recall are specified as deferred methods in BaseMenu, and called by
     BaseMenu's 'exec' method. 'setKeys' sets the left and right arrow keys
     to refer to the 'moveLeft' and 'moveRight' methods, also defined in
     PullDnMenu. 'clearKeys' clears these settings.
     
     Notice here that a bit of foresight was required to actually put the
     calls to these deferred methods in BaseMenu. In practice, you might
     find when defining a class lower down in the hierarchy, that you need
     to modify a class further up the tree to make it more generic. In this
     case, declaring and calling the deferred key setting methods in
     BaseMenu have made it more generic, allowing inherited classes to
     remap the keyboard as desired, just by defining two methods.
     
     Increasing generality is one of the only valid reasons to modify an
     existing class when inheriting from it. If instead we modified
     BaseMenu by making it more specific, for example by drawing a window
     around its menu, all the subclasses would inherit this behavior, or be
     forced to override it, which would be inefficient. Classes near the
     top of the inheritance tree should be, and are, more general, and they
     get more specific as the tree expands downwards.
     
         /*
             PullDnMenu.PRG

             Copyright (c) 1991, 1992 Chris Muller and Anton van Straaten
         */

         #include "class(y).ch"
         #include "win.ch"
         #include "inkey.ch"


         CREATE CLASS PullDnMenu FROM PopupMenu
         PROTECTED:
             METHOD  menuTop, menuLeft

         EXPORT:
             METHOD  moveLeft, moveRight
             METHOD  setKeys, clearKeys
         END CLASS


         METHOD menuTop
         RETURN winTop() + 1


         METHOD menuLeft
         RETURN winLeft() + ::parent:newMenuPos()


         METHOD moveLeft
             KEYBOARD CHR(K_ESC) + CHR(K_LEFT) + CHR(K_ENTER)
         RETURN self


         METHOD moveRight
             KEYBOARD CHR(K_ESC) + CHR(K_RIGHT) + CHR(K_ENTER)
         RETURN self
         
         
         METHOD setKeys
             SET KEY K_LEFT  TO ::moveLeft
             SET KEY K_RIGHT TO ::moveRight
         RETURN self
         
         
         METHOD clearKeys
             SET KEY K_LEFT  TO
             SET KEY K_RIGHT TO
         RETURN self
         
         // eof pulldnme.prg

3.4.8. The menu demonstration
     
     The demonstration program, MENUDEMO.PRG, is a normal procedural
     program which uses the menu objects to display a menu. In practice,
     you would probably want to make a routine like this data-driven, so
     that the details of the menu layout are read in from a configuration
     file. However, the purpose of this demonstration program is merely to
     show how the menu objects can be created and used.
     
     Pull-down menu systems tend to be nested structures by their very
     nature, and the code in MENUDEMO reflects this. Using the methods in
     the classes we have written, there are various ways in which a menu
     could be defined. On the one hand, an empty menu could be created,
     after which items could be added to it one by one. This approach is
     demonstrated in the comment near the end of the program. At the other
     extreme, you can nest your calls to the menu constructor as deep as
     you like, for example:
     
     oMenuBar:addItem(" File ",                 ;
          PullDnMenu():new( {                   ;
               { " Load ", { || LoadFile() } }, ;
               { " File ", { || FileOpt()  } }, ;
               { " Save ",                      ;
                    PopupMenu():new( {          ;
                         { "Document ", { || SaveDoc()  } }, ;
                             { " Text    ", { || SaveText() } }, ;
                   }) ) )
     
     ...but this gets rather hard to read!  In MENUDEMO.PRG, we have taken
     a middle path, defining one menu at a time and assigning them to
     variables until they are needed. This means that the menu has to be
     implemented in reverse, defining the deepest menus first (a bit like
     Reverse Polish Notation on an HP calculator).
     
     The nested arrays and code blocks do make the code look a bit icky,
     but again, data-driving the menu would do away with such problems.
     
     As discussed earlier, if this demonstration program were more object
     oriented, it would not use code blocks at all; instead, all the
     actions would be objects of some kind. The entire system could then
     consist of objects, each with their own specific task, and in this
     case all tied together by the menu.

3.5. Actual execution
     
     To get an idea of what happens during actual execution, let's ignore
     the creation of the menu objects, which in principle we should already
     understand, and look at what happens when the statement
     'oMenuBar:exec()' is executed.
     
     Because MenuBar does not directly implement an exec method, the exec
     method in the superclass, BaseMenu, is invoked. Once into the menu
     loop, the first thing this method does is to draw the menu by sending
     the 'draw()' message to the 'self' object with the statement
     '::draw()'.
     
     It is important to realize that even though we are now executing a
     BaseMenu method, the 'self' object at this point is not an instance of
     BaseMenu, but rather an instance of MenuBar, as referred to by the
     variable 'oMenuBar'.
     
     Because of this, the 'draw' method that now gets invoked is MenuBar's
     'draw' method; we are now back down in the MenuBar class. But after
     this method has drawn a bar across the top of the screen, it
     explicitly invokes 'draw' in the superclass - and we're back in a
     BaseMenu method!
     
     Once BaseMenu's 'draw' has executed and displayed all the menu items,
     it returns to where it was invoked, which was MenuBar's 'draw'; this
     in turn returns to BaseMenu's 'exec', where execution continues.
     
     We could continue describing this flow of control for some time, but
     we have illustrated the basic point, which is how execution switches
     up and down the inheritance tree depending on where methods have been
     defined.
     
     This can be tricky to come to grips with; again, tracing through the
     code in the debugger can help a great deal.

                                <end>
