















                             GCOOPE Version 1.0

     Generic C-language Object Oriented Programming Extension Version 1.0

                             by Brian Lee Price  

                    Released as Public Domain July, 1994



                                   Table of Contents


            I. Introduction...............................................1
               What is PCOOPE ?


           II. Version 1.0 Ancestory......................................2
               Design goals


           III. The Kernel System.........................................3
                Overview

                A. List manager...........................................3
                   List based nature of version 3.1

                B. Object list............................................3
                   The object tracking system

                C. Generic function list..................................4
                   Generic (virtual) function database

                D. The garbage collector and memory management shells.....5
                   Temporary object management

                E. Function dispatcher module.............................6
                   with instance memory management

                F. The pseudo class 'Object'..............................6
                   Default method installation

                G. The pseudo class 'Class'...............................7
                   Class system installation

                H. Other planned pseudo classes...........................7
                   Extending the kernel


           IV. High Level Data Structures.................................7
               Dynamic structures in the PCOOPE kernel

               A. Object handles..........................................7
               B. Instance Data Block.....................................8
               C. Class Definition Data Block.............................9

            V. Kernel Theory of Operation................................11
               By module and function

               A. listmgr.c module.......................................11
                  1. addItem.............................................11
                     Private Function

                  2. rmvItem.............................................12
                     Private Function

                  3. compactList.........................................12
                     Private Function

                                           i



               B. objlist.c module.......................................13
                  1. getObject...........................................13
                     Private Function

                  2. getObjDef...........................................14
                     Private Function

                  3. addObject...........................................14
                     Private Function

                  4. rmvObject...........................................15
                     Private Function

               C. generic.c module.......................................15
                  1. tagCmp..............................................16
                     Public Function

                  2. addGeneric..........................................16
                     Private Function

                  3. rmvGeneric..........................................16
                     Private Function

                  4. getMthd.............................................17
                     Private Function

                  5. addMethod...........................................17
                     Private Function

                  6. rmvMethod...........................................17
                     Private Function

               D. garbage.c module.......................................18
                  1. garbage.............................................18
                     Private Function

                  2. makePerm............................................19
                     Public Function

                  3. outOfElems..........................................19
                     Private Function

                  4. s_calloc............................................19
                     Public Function

                  5. s_free..............................................20
                     Public Function

                  6. s_malloc............................................20
                     Public Function

                  7. s_realloc...........................................20
                     Public Function

               E. funcdisp.c module......................................21
                  1. g...................................................21
                     Public Function

                                          ii



                  2. steer...............................................22
                     Public Function

                  3. getIVptr............................................22
                     Public Function

                  4. initInst............................................23
                     Private Function

                  5. makeInst............................................23
                     Public Function

                  6. getCVptr............................................24
                     Public Function


           VI. Pseudo Class Descriptions.................................25
               Definition of pseudo class

               A. Object pseudo class module.............................25
                  1. Object_Install......................................25
                     Public Function

                  2. kill................................................26
                     Default method for Kill generic

                  3. err.................................................27
                     Default method for Err generic

                  4. getClassOf..........................................27
                     default for classOf generic

                  5. getIVsize...........................................28
                     default for ivSize generic

                  6. defRespondsTo.......................................28
                     default for respondsTo generic





















                                          iii





                          GCOOPE Version 1.0 SDK Debug Kernel

                              Technical Reference Manual

                         Written by Brian Lee Price, July 1994



           I. Introduction


                     What is GCOOPE ?  Every few days I ask myself this
                question, and I always come up with a different answer.
                Originally conceived and designed as an object oriented
                programming extension to the C programming language,
                GCOOPE's inherent flexibility makes it something more.

                     GCOOPE is an experimental/educational Object Oriented
                Programming environment for standard ANSI C.  While the
                following paragraphs will mention a number of possible
                futures for the package, much work needs to be done in
                co-operation with the user's group before it achieves even a
                fraction of its potential.  In truth, the structure of
                GCOOPE may not prove itself to be suitable for commercial
                applications.  In the meantime, or in any case, it is an
                instructive exploratory framework for experimentation and
                research into the OOP world.

                     Is it SmallTalk for C ?  Not without a preprocessor it
                isn't, but it is similar.  It is worth noting that many
                Smalltalk techniques will work quite well in the GCOOPE
                framework.

                     Is it an operating system ?  Well, it is an operating
                system for objects, but no it doesn't have the potential to
                be a true operating system.  (Yet, I will admit to
                daydreaming about a GCOOPE accelerator in hardware. :).

                     Is it an applications framework ?  It could become one
                once it has been ported to enough systems and appropriate
                platform dependant expansion modules are written to a
                standardized interface, after all, portability is a key
                issue.

                     Is it a system resource ?  Well, not right now, but if
                you encapsulated the kernel as a DLL (or similar construct)
                and provided instantized kernel memory,...or GCOOPE on a
                MACH kernel ?

                     One of my main concerns in designing and writing GCOOPE
                is not to arbitarily close the door to any expansion
                possibility.  The last word on what GCOOPE is will be
                written in the future.  In the meantime, explore....



                                           1


           II. Version 1.0 Ancestory


                     Version 1.0 of the GCOOPE system has been designed to
                correct some deficiencies in PCOOPE version 2.1 and 3.0, as
                well as to better support advanced features.  The primary
                design goals have been:

                     1.  Ease of use.
                     2.  Kernel modularity.
                     3.  Kernel expandability.
                     4.  Future dynamic linking and loading support.
                     5.  Future multi-tasking support.
                     6.  Increased flexibility.
                     7.  Memory efficiency.

                    Fortunately, a number of these goals go hand in hand.  I
                adopted a few early strategies to achieve these goals.  A
                modular kernel (written correctly) is an expandable one. An
                expandable kernel lends itself to implementing flexible
                approaches.  Encapsulation of the kernel and class
                definitions make it easier to support dynamic linking and
                loading.  A side effect (or a method of) encapsulation is a
                simpler interface which (hopefully) will make the package
                easier to use.

                    A glaring shortcoming of PCOOPE version 2.1 was its poor
                memory efficiency.  Another related problem was that of
                memory fragmentation.  GCOOPE Version 1.0 does much to
                remedy the situation:

                     1.  'Flag' classes normally require no instance
                          variable memory.

                     2.  Instance variable memory is concatenated, ie. the
                          inherited instance variable memory is included in
                          the owning instance memory block.

                     3.  All internal tracking data is maintained in dynamic
                          tables, these tables are always a multiple of a
                          minimum number of elements in size.  This reduces
                          the need for reallocs and the resulting
                          fragmentation.

                     In summary, although the basic nature of GCOOPE remains
                the same as the PCOOPE system, this implementation has an
                overhauled design approach.  If you liked the concept behind
                PCOOPE, you'll be suitably impressed by GCOOPE.











                                           2


           III. The Kernel System


                A. List manager.

                          Version 1.0 is based on lists.  Central to this
                     approach is the list manager.  The list manager in V1.0
                     is a cross between traditional fixed element size list
                     management techniques and a partial implementation of a
                     memory manager.

                          Each list has a header structure detailed in
                     gcstruct.h. These headers maintain the current pointer
                     to the dynamically allocated list, the size of the
                     list's elements, the maximum number of elements in the
                     currently allocated list size, and a dual purpose index
                     to the first free element slot.

                          The list manager (source code in listmgr.c) is
                     suitable for ordered or unordered lists.  It has three
                     routines (addItem, rmvItem, and compactList) and is
                     self-initializing.  This simple approach allows the
                     code to be re-used many times in the kernel.  The
                     manner in which the list manager is implemented also
                     makes it suitable for maintaining lists of lists.

                          There are two major lists in V1.0; the object
                     list, and the generic function list of lists.  The
                     object list is a simple unordered list, and the generic
                     function list of lists is an unordered list of lists
                     ordered by class tag.


                B. Object list.

                          It really makes no difference conceptually whether
                     objects are referenced by a pointer to a memory
                     location or by an index to a table.  Previous versions
                     of GCOOPE used the pointer approach, while workable, it
                     directly led to many of the memory problems.  Version
                     1.0 uses the index approach, the object list is a
                     dynamic table of objectEntry type structures.  These
                     structures contain a pointer to the object's memory,
                     the ID of the process they belong to, and a use
                     indicator used by the garbage collector to determine
                     which objects can safely be deleted.

                          The object list doubles as the garbage collector
                     buffer, so in reality, compared to earlier approaches,
                     this approach uses very little additional memory.  In
                     fact, due to the organization of the instance memory
                     blocks, it uses quite a bit less.







                                           3


                          I should point out here that although the type
                     object, which is used as the object handle, is 32 bits
                     or more in size, only 15 bits are available for object
                     table indexing.  In both the source code and the
                     documentation, you will see many references to 'tag'
                     value.  This is simply the least significant 16 bits of
                     the object handle.


                C. Generic function list

                          The basic list of generic functions is very
                     similar to the object list, each entry contains a
                     generic function tag value (used as the index), an
                     optional default method address, and a pointer to a
                     dynamically sized list of methods for that function,
                     indexed by class tag.  Each entry in the list of
                     methods has a second class tag called owner.  This
                     owner tag is used by the current instance tracking
                     mechanism, it is the class tag of the class for which
                     the method is defined rather than inherited.






































                                           4


                          The default method may be called explicitly by
                     passing the class handle Object as the first parameter.
                     Otherwise, if no class method exists for the calling
                     class in the called generic function, and if a default
                     method exists, it will be called.  More detail on the
                     actual use of the polyList will appear in the section
                     on the function dispatcher.

                D. The garbage collector and memory management shells

                          In V1.0 the garbage collector is very similar to
                     the PCOOPE system in V2.1, the only real differences
                     are the use of the object list instead of a dedicated
                     buffer, the addition of process ID awareness, and the
                     direct interface with the memory management shell
                     routines.

                          There are a number of good reasons to use memory
                     management shells with the GCOOPE system.  Number one
                     is the need for co-operation between the garbage
                     collector and the memory management functions, next is
                     the effect of eliminating the need for checking the
                     return pointer for a NULL pointer condition.  As long
                     as the operation of the default error handler is not
                     modified, a NULL pointer will never be returned.  The
                     most subtle reason is to provide a one stop shop for
                     upgrade to an aftermarket memory manager library.

                          When you examine the source code for the garbage
                     collector system, you will see references to the
                     adaptive nature of the garbage collector routine.
                     Basically, depending on the setting of certain
                     constants in gcstruct.h, the garbage collector has two
                     distinct modes.  In the normal mode, the garbage
                     collector only examines a few entries in the list each
                     time it is called and it only subtracts a small value
                     from the last access variable.  As the counter timeVal
                     times out, the garbage collector control variables will
                     be set to a slower pace, when a memory error occurs,
                     they will be set to a faster rate.  In the memory error
                     mode the garbage collector no longer pays any attention
                     to the process ID (except for the permanent process ID)
                     and runs at the maximum values allowed by the constant
                     settings.

                          In effect, the garbage collector system operates
                     probabilistically, with the adaptive algorithm
                     approximating a first order low pass filter.  As far as
                     overall processing time is concerned, there are many
                     more efficient approaches, but because the garbage
                     collector operates much like a background task, the
                     overall effect is much quicker in operation than most
                     other algorithms.  (Plus its simple.)






                                           5


                E. Function dispatcher module

                          In PCOOPE Version 2.1 I hid the function
                     dispatcher behind macros and used a number of of global
                     variables to track methods for each generic function.
                     This proved cumbersome in practice, with GCOOPE the
                     function dispatcher is out in the open (so to speak)
                     and the entire generic function tracking system is
                     implemented via the generic function list.

                          The function dispatcher takes a generic type
                     parameter and through some creative use of the va_...
                     function/macro accesses the first parameter in the call
                     to the method.  The first parameter in a method call is
                     always of type object and is the object handle for the
                     instance or class being operated on.  The function
                     dispatcher gets the list indexed by the generic
                     parameter and looks up the class of the object handle,
                     if a match is found it will adjust the object handle to
                     point to the correct instance and return the method.
                     However if either the object handle is equal to
                     'Object' or no match is found, the method returned will
                     be that of the default method.  If no default method is
                     registered for the generic function being accessed the
                     method returned will be that of the default error
                     handler.

                          Without going into too much detail (this IS
                     supposed to be an overview), the function dispatcher
                     and memory access system has been completely overhauled
                     from the PCOOPE approach.  The index to the object
                     table, along with a current instance offset, and a flag
                     class value are all compacted in a 32 bit object
                     handle.  The instance memory block has been
                     concatenated.  In other words all ancestor instances
                     are part of the same memory block as the owning class
                     instance.

                          Routines are provided in this module to access the
                     instance and class variables as well as to create an
                     instance block.  There is also a routine dedicated to
                     updating the current instance pointer, normally this is
                     done automatically, however in certain cases it must be
                     called directly.  (Cases such as inside a New, Kill, or
                     Err method).


                F. The pseudo class 'Object'

                          Because the class mechanism has not yet been
                     installed prior to installation of 'Object', 'Object'
                     installs itself using low level kernel functions.  In
                     fact, 'Object' is not a true class because its methods
                     are installed as the default methods for the
                     generictions it loads.  You should not inherit
                     'Object', its methods are always available.



                                           6


                G. The pseudo class 'Class'

                          Similar to 'Object', 'Class' installs using low
                     level kernel functions.  'Class' actually is a true
                     class with methods that are installed as generic
                     methods, however, there is no point to inheriting the
                     class 'Class' since it only deals with the process of
                     installing a class definition object into the GCOOPE
                     kernel.  Once 'Class' has been loaded, normal class
                     definitions may be installed.


                H. Other planned pseudo classes

                          Using the techniques and methods used by and made
                     available through 'Object' and 'Class' it is possible
                     to install other pseudo class modules for the purpose
                     of extending the kernel and the pseudo-classes 'Object'
                     and 'Class'.  Such extensions may be used to add
                     dynamic loader/unloader capabilities, multi-tasking,
                     platform GUI support, etc.

                          With the framework provided it is possible to add
                     library functions, generic functions, methods and
                     default methods to existing generic functions, and
                     global variables.  All added functions and variables
                     could be published and made available through an add on
                     symbol list manager for dynamic loading support.


           IV. High Level Data Structures


                NOTE: in the following discussion, it is assumed that you
                have a hardcopy of the file gcstruct.h.

                A. Object handles

                          The typedef for 'object' insures that its size
                     will be at least 32 bits.  The type object is used in a
                     variety of ways in GCOOPE, here we will examine the
                     structure imposed on a variable of type object when it
                     is used as an object handle.

                     ---------------------------------------
                     | 31 FLAG | 30 FEXT 16 | 15   TAG   0 |
                     ---------------------------------------

                               OBJECT HANDLE STRUCTURE

                          The actual structure definition for this structure
                     is given in gcstruct.h as objHndl.

                     TAG is an index to the objList list for the object.  It
                     may be accessed through the tag member of objHndl.




                                           7


                          FEXT is the offset from the start of the instance
                     memory block to the current instance.  The current
                     memory block is located at the address given by the
                     objDef member of the objectEntry structure indexed by
                     TAG.  FEXT may be accessed through the fext member of
                     objHndl.

                     FLAG is cleared to 0 for classes and normal instances,
                     for instances of special 'flag' classes which impose a
                     custom structure onto the OBJECT HANDLE STRUCTURE, FLAG
                     is set to 1.  When FLAG is set, FEXT is the actual
                     class tag value.  These flag classes either have no
                     instance variables or they use the object handle for
                     instance variable storage.

                          It should be noted that the type object is the
                     default return type for methods.  You should cast the
                     return value to the appropriate type.  The type object
                     is capable of passing any data type of 32 bits or less
                     in size.


                B. Instance Data Block

                          The basic structure of an instance data block is
                     simple, it consists of an integer class tag value
                     followed by a variable number of bytes where the
                     instance data can be/is stored.  If the class of an
                     instance inherits other classes, those instance data
                     blocks will be appended to the end of the owning
                     instance data block.  Where it gets a bit complicated
                     is the common case where the inherited class instance
                     data block has its own inherited instance data blocks
                     appended.

                          The following is a graphical explanation of the
                     instance data block structure for the three cases
                     described:

                     -----------------
                     | class tag     |
                     -----------------   BASIC INSTANCE BLOCK
                     | instance vars |
                     -----------------

                     -------------------------
                     | owning class tag      |
                     -------------------------
                     | instance vars         |     INSTANCE BLOCK WITH
                     -------------------------
                     | inherited class 1 tag |        TWO ANCESTORS
                     -------------------------
                     | instance vars         |
                     -------------------------
                     | inherited class 2 tag |
                     -------------------------
                     | instance vars         |
                     -------------------------

                                           8



                     -----------------------------
                     | owning class tag          |
                     -----------------------------
                     | instance vars             |
                     -----------------------------
                     | parent 1 class tag        |     INSTANCE BLOCK WITH
                     -----------------------------
                     | instance vars             |     TWO ANCESTORS, EACH
                     -----------------------------
                     | grandparent 1-1 class tag |     WITH TWO ANCESTORS OF
                     -----------------------------
                     | instance vars             |     THEIR OWN
                     -----------------------------
                     | grandparent 1-2 class tag |
                     -----------------------------
                     | instance vars             |
                     -----------------------------
                     | parent 2 class tag        |
                     -----------------------------
                     | instance vars             |
                     -----------------------------
                     | grandparent 2-1 class tag |
                     -----------------------------
                     | instance vars             |
                     -----------------------------
                     | grandparent 2-2 class tag |
                     -----------------------------
                     | instance vars             |
                     -----------------------------

                          Additional levels of inheritance follow the rules
                     described and implied in the above.


                C. Class Definition Data Block

                          As you can see from the above, while the layout of
                     the instance data blocks is straight forward, keeping
                     track of it is not.  This is the job of the class
                     definition data block.  Rather than reprinting the
                     relevant portions of gcstruct.h, I'll refer you to them
                     as needed in the following explanation.

                          The first entry in a class definition data block
                     is always a classEntry type structure (described in
                     gcstruct.h).  The first member of that structure
                     (class) is set equal to the class tag value.  Member
                     cvSize is set to the size of the class variables data
                     area that is shared by all instances of the class.
                     Member ivSize is the size of the class's own instance
                     variables and totSize is the total size of an instance
                     data block for that class (this includes inherited
                     instance data blocks).





                                           9


                          The numSuper member is the number of immediate
                     superClasses inherited (parents). Member numMthds is
                     the number of defined (not inherited) method functions
                     for the class, while member  cVars is the beginning of
                     the class variables storage area.

                          The next area is comprised of numSuper's worth of
                     superEntry structures (see gcstruct.h) and is the data
                     storage area for the instance tracking mechanism.  Each
                     entry consists of a class tag value and the offset from
                     the start of the child class's instance memory block
                     where the superClass instance memory block begins.

                          Note that the class member of a superClass entry
                     will match the class tag value located at the given
                     offset within the child instance block.  To remain
                     memory efficient, only the immediate parents are
                     listed, however because of the layout of the instance
                     memory block(s), you can find the offset for a
                     great-great-...etc. grandparent instance simply by
                     adding the offsets for each successive parent in the
                     direct lineage.

                          The tail end of the class definition data block is
                     the method data area.  This area begins at the end of
                     the superEntry list.  It consists of numMthds worth of
                     methodEntry type structures (see gcstruct.h), each
                     entry contains the generic index value of the generic
                     function through which the method is accessed, and the
                     address of the method function.  This area is primarily
                     used for inheritance purposes although it could play a
                     roll in dynamically unloading a class.



























                                          10


           V. Kernel Theory of Operation

                     In the following descriptions, Private Function means
                that the functions is meant to be called only from within
                the kernel.  Public Function indicates that it will be made
                available to applications programs.


                A. listmgr.c module

                          As noted it the Overview, version 1.0 is based on
                     lists.  Basic list management is performed by the
                     listmgr module.  In the following discussion, please
                     refer to the DYNLIST_STRU macro and the dynList
                     structure typedef in gcstruct.h.  The dynList structure
                     (and all structures beginning with the DYNLIST_STRU
                     macro) has (at least) the following members:

                     elemSize - this is the size in bytes of an element of
                               the list.

                     firstFree - the index value of the first unused slot
                               (element) in the list.

                     maxElems - the maximum number of elements in the
                               current list size.

                     listPtr - a pointer to the actual list.  Note: the
                               functions in listmgr will alter the address
                               stored here so it should not be locally
                               stored.

                          The listmgr module contains three functions;
                     addItem, rmvItem, and compactList.  Their operation is
                     detailed below.

                     1. addItem

                          usage:
                               newItemIndex=addItem(listControlStrucAdr,
                                                        elemSize);

                          error value: returns -1 on error.

                          prototype:

                               int addItem(void *, int);

                               This routine adds an item to a list control
                          structure whose first structure elements are
                          equivalent to a dynList structure.  If the member
                          listPtr is NULL, the list will be created and
                          initialized.  Note that the size of a list
                          created/managed always has the maxElems equal to a
                          multiple of the constant MIN_LIST_ADD.  The actual
                          size of the list is given by elemSize times
                          maxElems.


                                          11


                               If on entry, firstFree is equal to or greater
                          than maxElems, the list will be increased in size
                          by MIN_LIST_ADD elements.  The structure member
                          firstFree will be set to the next unused element
                          in the list and the index value of the new element
                          will be returned.  In order to be considered
                          unused, an element slot must contain all zeros.
                          This is a private kernel function.


                     2. rmvItem

                          usage:

                               nextFree=rmvItem(listControlStrucAdr,
                                                        elementIndex);

                          error value: returns -1 on error.

                          prototype:

                               int rmvItem(void *, int);

                               This routine frees up a previously occupied
                          slot, it does not reduce the total list size.  The
                          element freed will be zeroed out, and if the freed
                          element index is less than the current firstFree,
                          firstFree will be set to the index of the freed
                          element.  Normally, this routine returns the new
                          firstFree.  This is a private kernel function.


                     3. compactList

                          usage:

                               status=compactList(listControlStrucAdr,
                                                        booleanSorted);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               stat compactList(void *, boolean);

                               This routine attempts to free up unused
                          memory in a list.  The boolean type booleanSorted
                          when true tells the routine that it may perform
                          the compaction operation, squeezing out unused
                          slots.  This compaction process should only be
                          done on sorted lists because an indexed list would
                          become un-indexed.
                               Regardless of whether or not the list has
                          been compacted, this routine will check to see if
                          enough empty slots exist at the top of the list to
                          justify reallocating it.  This is a private kernel
                          function.


                                          12


                B. objlist.c module

                          This module provides the object database routines
                     for the kernel.  Each object (with certain specific
                     exceptions, namely the flag class instances) that is
                     active will have an entry in the objList structure's
                     list.  These entries conform to the structure typedef'd
                     as objectEntry.  This structure has three entries:

                     objDef - a pointer to the object's memory block.

                     procID - the process ID number of the process that
                               created the object.

                     lastAcc - a use indicator used by the garbage
                               collector.

                          Note that the list maintained in the objList
                     control structure is an unordered list.  The entries
                     are located by the object handle tag values which are
                     indices to the list.  The objlist.c module contains
                     four functions; getObject, getObjDef, addObject, and
                     rmvObject.  These functions are detailed below.


                     1. getObject

                          usage:

                               objectEntryPtr=getObject(object_tag_value);

                          error value: returns NULL on error.

                          prototype:

                               objectEntry * getObject(int);

                               This routine returns the pointer to a
                          structure objectEntry in the list maintained in
                          objList at the index equal to the tag value
                          object_tag_value.  This is a private kernel
                          function.

















                                          13


                     2. getObjDef

                          usage:

                               objDefinitionPtr=getObjDef(object_tag_value);

                          error value: returns NULL on error.

                          prototype:

                               void * getObjDef(int);

                               This routine returns a pointer to the actual
                          object definition instead of the objectEntry like
                          getObject.  Otherwise it is the same as getObject.
                          This is a private kernel function.


                     3. addObject

                          usage:

                               newObjTagValue=addObject(objectDefinitionPtr,
                                                             processID);

                          error value: returns BAD_OBJ on error.

                          prototype:

                               int addObject(void *, unsigned char);

                               The value processID is used to enable the
                          garbage collection mechanism to be multi-thread
                          aware, it is also used by makePerm and in newClass
                          to prevent the garbage collector from killing off
                          non-temporary objects by setting the value to
                          PERM_PROC_ID.

                               The object definition pointer must be a valid
                          pointer to an actual object definition.  The
                          return value is the tag value of the new object.
                          This is a private kernel function.

















                                          14


                     4. rmvObject

                          usage:

                               functionStatus=rmvObject(object_tag_value);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int rmvObject(int);

                               This function removes an object Entry from
                          the objList after freeing the object definition
                          memory area pointed to by objDef (if it is !=
                          NULL).  It returns FUNCOKAY if no error.  This is
                          a private function.



                C. generic.c module.

                          This module tracks the generic functions and their
                     methods.  They are maintained in an unordered list of
                     generic functions, with each generic function entry
                     having an associated pointer to an ordered lists of
                     methods.  The generic function entries are contained in
                     structures of type genEntry.  Note that genEntry
                     structures begin with the DYNLIST_STRU macro, this
                     means that they have the same capabilities as a dynList
                     structure in regards to the routines in listmgr.c.

                          In addition, these structures have a member
                     defMthd, used to store the (optional) default method
                     address.

                         The method lists for each generic function are
                     comprised of genMethod type structures.  These
                     structures are sorted according to their first member
                     'class'.  This member is the class tag of the owning
                     instance in calls to the function dispatcher.  The next
                     member, owner, is the class tag of the class for which
                     the method is defined rather than inherited.  This
                     member is used by the instance tracking mechanism to
                     insure correct instance referencing.

                          The last member of the structure is the address of
                     the associated method.  This module contains six
                     functions; intCmp, addGeneRic, rmvGeneRic, getMthd,
                     addMethod, and rmvMethod.  These functions are detailed
                     below.








                                          15


                     1. tagCmp

                          usage:

                               used by qsort, bsearch, etc type standard
                                         ANSI-C library functions.

                          error value: none.

                          prototype:

                               int tagCmp(void *, void *);

                               This function is a simple tag compare routine
                          designed for use with the standard library qsort,
                          bsearch, etc. routines.  This is a public
                          function.


                     2. addGeneric

                          usage:

                               newGenericIndex=addGeneric(symbolStringPtr,
                                                             defaultMethod);

                          error value: returns MAX_GEN on error.

                          prototype:

                               Generic addGeneric(char *, method);

                               This function adds a new Generic function to
                          the genList.  It also installs the defaultMethod
                          for the new entry.  It returns the index value
                          (Generic tag) of the new entry which is used as
                          the handle to the Generic function in calls to the
                          function dispatcher.  This is a private kernel
                          function.

                     3. rmvGeneric

                          usage:

                               status=rmvGeneric(Generic_tag_of_func2rmv);

                          error value: returns -1 on error.

                          prototype:

                               int rmvGeneric(Generic);

                               This function attempts to remove the Generic
                          function indexed by Generic_tag_of_func2rmv.
                          Normally a non-zero positive number will be
                          returned.  This is a private kernel function.



                                          16


                     4. getMthd

                          usage:

                               genMethodPtr=getMthd(Generic_tag,
                                                             class_tag);

                          error value: returns NULL on error.

                          prototype:

                               genMethod * getMthd(Generic, int);

                               This function will lookup the correct Generic
                          function entry indexed by Generic_tag and do a
                          binary search for the genMethod entry in its
                          method list for class_tag.  It returns a pointer
                          to the genMethod type structure with a class entry
                          that matches class_tag.  This is a private kernel
                          function.


                     5. addMethod

                          usage:

                               status=addMethod(Generic_tag,method_address,
                                            class_tag, owning_class_tag);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int addMethod(Generic, method, int, int);

                               This function adds a method to the method
                          list of an existing Generic function.  It sorts
                          the list by class after filling in the new entry.
                          Normally this routine returns FUNCOKAY.  This is a
                          private kernel function.


                     6. rmvMethod

                          usage:

                               status=rmvMethod(Generic_tag, class_tag);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int rmvMethod(Generic, int);

                               This function will remove a previously
                          installed method from a Generic function's method
                          list.  It normally returns FUNCOKAY.  This is a
                          private kernel function.

                                          17


                D. garbage.c module.

                          This module is home to the memory management
                     functions for the kernel.  It also provides for
                     automatic destruction of temporary objects as well as
                     the means to make a temporary object permanent.

                          There are seven functions in this module, garbage,
                     makePerm, outOfElems, s_calloc, s_free, s_malloc, and
                     s_realloc.  They are described below.

                     1. garbage

                          usage:

                               garbage();

                          error value: none.

                          prototype:

                               static void garbage(void);

                               This function is a round-robin style garbage
                          collector routine with adaptive features.  It
                          searches the objList for unused objects and calls
                          p(Kill)(... to delete them.  It is multi-process
                          aware, under normal circumstances, it will only
                          examine objects which belong to the currently
                          executing process.  When an out of memory (or out
                          of list space) condition occurs, it will kick into
                          high gear and ignores process IDs.

                               The algorithm is adaptive, a use-based timer
                          is employed, on time-out the algorithm will be
                          reset to slower values.  At the end of an out of
                          memory condition, it will reset to faster values.
                          To gain a full understanding of this function, it
                          is recommended that you examine the source code in
                          detail.  A full discussion of its operation would
                          require a separate document.  This is a private
                          kernel function.

















                                          18


                     2. makePerm

                          usage:

                               status=makePerm(object_handle);

                          error value: FUNCFAIL is returned on an error.

                          prototype:

                               int makePerm(object);

                               This function makes a temporary object into a
                          permanent one, thereby disallowing access to it by
                          the garbage collector function.  FUNCOKAY is
                          normally returned.  This is a public function.


                     3. outOfElems

                          usage:

                               outOfElems();

                          error value: none.

                          prototype:

                               void outOfElems(void);

                               This function basically fakes an out of
                          memory condition and calls the garbage collector.
                          It is provided for the unlikely event that the
                          objList runs out of list memory space.  It is also
                          used by the s_... functions to avoid code
                          duplication.  This is a private kernel function.


                     4. s_calloc

                          usage:

                               newBlockPtr=s_calloc(numItems, itemSize);

                          error value: returns NULL if default error routine
                                              returns instead of aborts.

                          prototype:

                               void * s_calloc(unsigned, unsigned);

                               This routine is used exactly like the
                          standard ANSI-C library routine calloc.  Unlike
                          the standard routine, this routine interfaces
                          directly with the garbage collector.  Returns a
                          pointer to a dynamically allocated block of memory
                          of size numItems*itemSize.  The new block will be
                          cleared to all zeros.  This is a public function.

                                          19


                     5. s_free

                          usage:

                               s_free(oldBlock);

                          error value: none.

                          prototype:

                               void s_free(void *);

                               This routine is mostly provided for
                          completeness, it behaves exactly as the standard
                          library free().  This is a public function.


                     6. s_malloc

                          usage:

                               newBlockPtr=s_malloc(size);

                          error value: returns NULL if default error routine
                                               returns instead of aborts.

                          prototype:

                               void * s_malloc(unsigned);

                               This routine is used exactly like the
                          standard ANSI-C library routine malloc.  Unlike
                          the standard routine, this routine interfaces
                          directly with the garbage collector.  It returns a
                          pointer to a new dynamically allocated block of
                          memory of size 'size'.  This is a public function.


                     7. s_realloc

                          usage:

                               newBlockPtr=s_realloc(oldBlockPtr, oldSize);

                          error value: returns NULL if default error routine
                                               returns instead of aborts.

                          prototype:

                               void * s_realloc(void *, unsigned);

                               This routine is used exactly like the
                          standard ANSI-C library routine realloc.  Unlike
                          the standard routine, this routine interfaces
                          directly with the garbage collector.  It returns a
                          pointer to the relocated and resized block of
                          memory of size 'newsize'.  This is a public
                          function.

                                          20


                E. funcdisp.c module.

                          This module is responsible for dispatching Generic
                     functions to the correct method, tracking the current
                     object instance, accessing class variables, and
                     creating/accessing instance variables.  This module
                     contains six functions; g, steer, getIVptr, initInst,
                     makeInst, and getCVptr.  They are described below.


                     1. g

                          usage:

                               methodReturnValue=g(GenericTag)(
                                                   object_handle,...);

                          error value: dispatches to the default error
                                         routine if an error occurs.

                          prototype:

                               method g(generic,...);

                               This routine dispatches the Generic function
                          indexed by GenericTag to the method in the method
                          list with a class equal to the tag value of
                          object_handle.  Due to the way C compiles the
                          statement given in usage, the method returned from
                          g will immediately be called upon the return from
                          g.  Another aspect of the function dispatcher g is
                          that it accesses the first parameter
                          (object_handle) in the call to the method.  In
                          most cases, g will update object_handle via a call
                          to steer.  This insures that further calls to
                          ancestor methods will be routed correctly and that
                          calls to getIVptr will return a pointer to the
                          correct instance memory block.

                               Normally, g will dispatch to the method that
                          corresponds to the class of the object_handle in
                          the method list maintained for the Generic
                          function indexed by GenericTag.  If a method for
                          that class does not exist, p will attempt to
                          return the default method, if no default method is
                          listed, the dispatcher will return the address of
                          the default error handler.

                               For further information about this complex
                          function, please consult the user's guide and
                          carefully study the provided source code.  If you
                          need further information or assistance contact me
                          via the GCOOPE USER'S GROUP.  This is a public
                          function.





                                          21


                     2. steer

                          usage:

                               updatedObjectHandle=steer(classObjectHandle,
                                              instanceObjectHandle);

                          error value: returns NULL on error.

                          prototype:

                               object steer(object, object);

                               This routine 'steers' the fext field of the
                          OBJECT HANDLE STRUCTURE to contain the offset
                          within the owning instance memory block referenced
                          by instanceObjectHandle for the class referenced
                          by classObjectHandle.  It normally returns the
                          updated object handle.

                               Most applications will never require this
                          function, however class definitions will make use
                          of it at least in the constructor method (New).
                          It will also be required for any destructor method
                          or error handling method.  In general, this
                          routine must be called directly any time you
                          attempt to call a method that is defined for both
                          the current object class and an ancestor object
                          class and you are trying to invoke the ancestor's
                          method.  Another place where it may be required is
                          when you use local method pointer caching (see the
                          user's guide).  This is a public function.


                     3. getIVptr

                          usage:

                               instancePtr=getIVptr(instanceObjectHandle);

                          error value: returns NULL on error.

                          prototype:

                               void * getIVptr(object);

                               This routine is used to access the current
                          instance memory area.  It gets the pointer to the
                          owning instance memory block, adds the fext value,
                          and adds the size of the first entry (an integer:
                          classTag).  It returns the adjusted pointer.  This
                          is a public function.







                                          22


                     4. initInst

                          usage:

                               status=initInst(class_tag, curOffset,
                                                             newBlockPtr);

                          error value: returns 0/NULL on error.

                          prototype:

                               object initInst(int, int, char *);

                               This routine is used by makeInst (see below)
                          to initialize a new instance memory block.  It is
                          a recursive function calling itself for each
                          immediate parent class of class_tag.
                          Initialization consists of writing the correct
                          class tag values at the correct offsets within the
                          new instance memory block.  Normally this routine
                          returns a non-zero value.  When examining the
                          source code for this routine, keep the previously
                          detailed description of the INSTANCE DATA BLOCK
                          close at hand.  This is a private kernel function.


                     5. makeInst

                          usage:

                               instancePtr=makeInst(
                                              ptrToInstanceObjectHandle);

                          error value: returns NULL on error.

                          prototype:

                               void * makeInst(object *);

                               This routine, when called by the
                          owning/creating class, will create a new instance
                          memory block and initialize it.  It will update
                          the Instance object handle pointed to by
                          ptrToInstanceObjectHandle with the new instance
                          object handle created.  If the calling class is
                          not the owner, it will simply dispatch to
                          getIVptr.  For a better explanation of the use of
                          this function consult the user's guide.  This is a
                          public function.










                                          23


                     6. getCVptr

                          usage:

                               classVariablesPtr=getCVptr(
                                                   classObjectHandle);

                          error value: returns NULL on error.

                          prototype:

                               void * getCVptr(object);

                               This routine will return a pointer to the
                          class variables area for the class given by
                          classObjectHandle.  This is a public function.











































                                          24


           VI. Pseudo Class Descriptions.

                     Pseudo classes are code modules which are not part of
                the kernel proper, but neither are they true class
                definition modules.  These are used for providing both
                necessary high level kernel functions and for kernel
                expansion.  An additional point is that pseudo classes may
                have actual class names and descriptions and they may also
                utilize generic functions.

                     In the basic GCOOPE system there are two linked pseudo
                classes; Object and Class.  They and their functions/methods
                are described below.

                A. Object pseudo class module

                          This module provides the default routines for the
                     Generic functions Kill and Err.  It also installs the
                     Generic function New although it provides no default
                     for it.  Additional informational 'Smalltalk' style
                     default functions are defined for the generic
                     functions: classOf, ivSize, respondsTo, deepCopy, and
                     shallowCopy.  This module contains eight functions;
                     Object_Install, kill, err, getClassOf, getIVsize,
                     defRespondsTo, defDeepCopy, and defShallowCopy.  They
                     are detailed below.


                     1. Object_Install

                          usage:

                               status=Object_Install();

                          error value: returns FUNCFAIL on error.

                          prototype:

                               stat Object_Install(void);

                               This routine installs the class 'Object' into
                          the kernel databases, it also installs the
                          defaults for the generic functions New, Kill, Err,
                          classOf, ivSize, respondsTo, deepCopy, and
                          shallowCopy.  Normally it returns FUNCOKAY.

                               Although Object is sort of a class, it cannot
                          be inherited.  Its purpose is to provide the basic
                          default methods for the kernel.
                               IMPORTANT NOTE: DO NOT under any
                          circumstances add methods to the class 'Object'.
                               This is a public function, however it should
                          only be called during kernel initialization.






                                          25


                     2. kill

                          usage:

                               result=g(Kill)(instanceHandle);

                          or direct call via:

                               result=g(Kill)(Object, instanceHandle);

                          error value: returns NULL on error after calling
                                              the default error routine.

                          prototype:

                               static object kill(object,...);

                               This routine is the default method for the
                          Generic function Kill.  It may also be called
                          explicitly by passing 'Object' as the first method
                          parameter.  This routine will take the place of a
                          missing class kill routine as well as actually
                          killing off the object when all the proper
                          conditions are met.

                               When used as a replacement for a missing
                          class Kill method, it performs the minimum
                          necessary duties for a class Kill method.  For
                          each direct parent class of the class for which it
                          is acting as a replacement routine, it will update
                          the fext field and call the Kill generic with the
                          updated object handle.  Thus it will call any
                          existing ancestor class Kill method.

                               When it is called explicitly and the fext
                          field of the second parameter is not zero, it will
                          simply return a non NULL value.  Else if called
                          explicitly and the fext field of the second
                          parameter is zero or if it was called as the
                          default to replace an owning class Kill method, it
                          will remove the instance object and free the
                          instance memory block.

                               For more information on the Kill generic see
                          the user's guide.














                                          26


                     3. err

                          usage:

                               result=p(Err)(objectHandle,...);

                          or direct call via:

                               result=p(Err)(Object, objectHandle,...);

                          error value: this version aborts at the end of the
                                     routine and does not return any value.

                          prototype:

                               static object err(object,...);

                               This routine is the default method for the
                          Generic function Err.  It may also be called
                          explicitly by passing 'Object' as the first method
                          parameter.

                               In the debug version of the kernel, (which
                          this is) the routine prints all available
                          information about the error to stderr and them
                          dumps the last 64 bytes on the stack.  After
                          printing this information, it aborts.


                     4. getClassOf

                          usage:

                               called via the generic classOf.

                          error value: (object) 0

                          prototype:

                            static object getClassOf(object instance,...);

                               This is the default function for the classOf
                          generic.  It returns the class of the passed
                          instance.  Like all default functions it may be
                          called explicitly by passing Object as the first
                          parm with the actual instance as the second parm.













                                          27


                     5. getIVsize

                          usage:

                               called via the generic ivSize.

                          error value: (object) -1

                          prototype:

                            static object getIVsize(object instance,...);

                               This is the default function for the ivSize
                          generic.  It normally returns the size of the
                          instance variable structure for a given class cast
                          as type object.


                     6. defRespondsTo

                          usage:

                               called via the generic respondsTo.

                          error value: returns (object) NULL.

                          prototype:

                            static object defRespondsTo(object instance,...)

                               This is the default function for the
                          respondsTo generic.  The parameter following the
                          actual instance object handle should be of type
                          generic.  This routine will return the method
                          address of any existing class method for the
                          combination of instance and generic.  The return
                          value is cast as type object.


                     7. defDeepCopy



















                                          28



                          usage:

                               called via the deepCopy generic.

                          error value: returns (object) 0 on error.

                          prototype:

                            static object defDeepCopy(object instance,...)

                               This is the default function for the deepCopy
                          generic.  It will duplicate the instance passed
                          creating a new instance, copying the instance
                          block, and returns the handle of the new instance.
                          Classes which maintain a dynamically allocated
                          area of memory should define their own methods for
                          deepCopy that correctly allocate and copy the
                          dynamic memory area.


                     8. defShallowCopy

                          usage:

                               called via the shallowCopy generic.

                          error value: returns (object) 0 on error.

                          prototype:

                           static object defShallowCopy(object instance,...)

                               This is the default method for the generic
                          function shallowCopy.  Immeadiately following the
                          instance handle should be the source handle.  This
                          function will only copy the current instance
                          portion of the source to instance.  It will not
                          work with instances of class Class, nor will it
                          work if the class of the current instance of
                          source is not the owner or an ancestor of the
                          destination instance - instance.  Normally it
                          returns the handle to the updated instance.
                              As with deepCopy above, special care needs to
                          be taken with classes that manage dynamic memory
                          or other system resources.













                                          29


                B. Class pseudo-class module.

                          This module provides the means for the
                     installation and initialization of class definitions
                     and forms the primary interface for those definitions.
                     It should be installed after Object and prior to any
                     other pseudo-classes or class definitions.  Although
                     Class actually is a true class, its inclusion of normal
                     functions and use of low level kernel functions makes
                     it a pseudo-class.  Additionally, Class is the one
                     class that cannot be inherited, or at least, I can't
                     think of any reason why you would want to.

                       This module contains six functions/methods; inhMthd,
                     newClass, addGMthd, rmvGMthd, killClass, and
                     Class_Install.  These are defined below.


                     1. inhMthd

                          usage:

                               status=inhMthd(classObjectHandle,
                                                   superClassObjectHandle);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int inhMthd(object, object);

                               This routine causes the class given by
                          classObjectHandle to inherit all of the methods
                          for superClassObjectHandle.  It normally returns
                          FUNCOKAY.

                               The main use of this function is its direct
                          use by newClass to inherit the methods of ancestor
                          classes, however, it is provided as a Generic
                          method for potential use by pseudo class modules
                          that add functionality to existing class
                          definitions.  This is a postulated possibility,
                          not a foreseen one.  It does however, present an
                          alternative method of class definition expansion.
                          Most likely this will end up on the
                          forgotten/unnecessary public function list.
                          However, this is a public function.












                                          30


                     2. newClass

                          usage:

                               myNewClass=p(New)(Class,"myNewClass",
                                         sizeofCVs,sizeofIVs, parent1,...
                                         parentx, END);

                          error value: returns END on error.

                          prototype:

                               static object newClass(object,char *,
                                                             int,int,...);

                               This is the method for genmorph New when the
                          first method parameter is Class.  It creates a new
                          class object, adding the name to the symbol list,
                          creating the class definition memory block,
                          initializing the block, adding the object to the
                          object list, inheriting all of the ancestor
                          classes in the parent list which is terminated by
                          END, and setting up the instance memory tracking
                          system for instances of the new class.

                               Normally it returns the object handle of the
                          new class object.  This method is a necessary part
                          of a class definition's installation procedure.
                          More detail on its use appears in the user's
                          guide.


                     3. addGMthd

                          usage:

                               status=addGMthd(objectHandleOfClass,
                                         GenericFunctionStringName,
                                                   addressOfNewMethod);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int addGMthd(object, char *, method);

                               This adds a new method to the named generic
                          function for the indicated class.  If the named
                          generic function does not exist, it will be
                          created.  Under normal conditions it returns
                          FUNCOKAY.  This is a public function.








                                          31


                     4. rmvGMthd

                          usage:

                               status=rmvGMthd(objectHandleOfClass,
                                    GenericFunctionStringName);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int rmvGMthd(object, char *);

                               This routine removes a class method from the
                          named Generic function.  Under normal conditions
                          it returns FUNCOKAY.  This is a public function.


                     5. killClass

                          usage:

                               result=p(Kill)(Class, classToKill);

                          error value: returns FUNCFAIL on error.

                          prototype:

                               static object killClass(object, object);

                               This method for Class kills a class object
                          given by classToKill.  It will remove all class
                          methods.  This feature is of limited use until a
                          dynamic loader add on module is defined.  Normally
                          this method returns FUNCOKAY.


                     6. Class_Install

                          usage:

                               status=Class_Install();

                          error value: returns FUNCFAIL on error.

                          prototype:

                               int Class_Install(void);

                               This installs the class 'Class' and adds
                          newClass and killClass to their respective Generic
                          functions.  Normally this routine returns
                          FUNCOKAY.  Although this is a public function, it
                          should only be called during initialization.





                                          32


           VII. Summary

                     The story of GCOOPE is far from complete, although the
                above described kernel functions, modules, and pseudo
                classes do form a self sufficient core that can be used to
                write programs without any additional modules except for
                user defined class definitions and an initialization
                routine.

                     Additions to the kernel such as a dynamic loader pseudo
                class module, a multi-tasker pseudo class module, etc. will
                have their own separate documents.  So this technical
                reference manual is complete for version 1.0 as it stands
                now.  The above material is presented primarily for the
                programmer who wants to either expand the kernel, introduce
                speed up routines, or otherwise modify it.  Any
                modifications should preserve the given prototypes and
                interface for public and Generic functions for compatibility
                reasons.








































                                          33


           Appendix A. Appendix A.  User's group Information.


                          JOIN THE GCOOPE USER'S GROUP!


                For a one year membership send check/money order in the
                amount of $20.00, (made payable to Brian Lee Price) to the
                address below:

                          Brian Lee Price

                          GCOOPE USERS GROUP

                          RD2 BOX239AA

                          CLEARVILLE, PA.  15535

                    Please include my middle name to avoid local post office
                    difficulties :).


                     User's group members receive the latest updates to the
                GCOOPE system, new class libraries, expansion modules, etc.
                Limited (5hrs/yr) free technical support over the phone is
                available, and access is granted to a User's group only
                private limited access bbs, you will be added to the
                quarterly newsletter mailing list, and other services are
                available.






























                                          34


           Appendix B. Appendix B.  Developer's notes to GCOOPE 1.0

                    This package is primarily intended for experimental,
                exploratory, and educational purposes.  It encorporates a
                Smalltalk like framework in a standard ANSI C compatible
                manner.  GCOOPE is the upgraded and revamped child of the
                PCOOPE package.  While similar in operation to its ancestor,
                GCOOPE provides a more programmer friendly environment and
                has much improved capabilities.

                    In the first release of the ancestor package, I made
                some claims and misleading statements which while
                unintentional, have given me cause to regret.  The ancestor
                package ended up reaching entirely the wrong audience, I was
                being contacted by professional programmers and commercial
                interests who believed it to be applicable to mainstream
                programming.  Unfortunately, my limited experience and lack
                of resources makes it currently impossible for me to develop
                the framework into its full potential as a commercial
                product.

                    GCOOPE and its ancestors are my learning environment for
                object oriented programming.  As I write and modify the
                package, I continually find new capabilities and alternate
                approaches that were not purposely designed into the
                package.  GCOOPE has been designed to be a modular,
                extensible, and easy to maintain package that offers as much
                flexibility as possible within its chosen approach to object
                oriented programming.

                    You will find that the basic class library included in
                the package is full of experimental and exploratory
                approaches.  This is because I am learning OOP and GCOOPE as
                I write them.  Prior to my involvement with the ancestor
                package, I had no experience in OOP.  Many of the
                improvements embodied in GCOOPE have come as a direct result
                of feedback from user's group members, in particular Norman
                Culver, and Mark Murphy.  It is hoped that future user's
                group members will provide a similar service for the GCOOPE
                package.

                    GCOOPE is not intended as a competitive alternative to
                C++, Smalltalk, or other commercial OOP approaches.  It is
                ludicrous to assume that one person working alone with a
                student's budget and only a year's experience in C
                programming could develop and support a full fledged
                commercial programming environment.  However I do believe
                that GCOOPE is suitable as an educational/experimental
                environment for exploring various topics in OOP.










                                          35


                    Technical support and upgrades are available only
                through the GCOOPE user's group.  In the works are speed up
                routines for the kernel functions, including platform
                dependant inline assembly optimizations, multi-tasking with
                threads, pipes, etc., primitive GUI class libraries, and
                dynamic loading support.  Currently, I am limited to the
                IBM-PC hardware platform with MS-DOS, however, I will be
                more than happy to assist any user's group member with ports
                of the package to Unix, Atari ST, MAC, etc.  In fact, if you
                are SERIOUS about doing the port, I'll throw in a free
                year's membership.  I would also be interested in
                co-operating with other programmers in the development of a
                commercial version of the GCOOPE framework, however to
                qualify you must be able to provide information and
                capabilities beyond what I have locally.

                    To summarize, GCOOPE is an educational and experimental
                approach to providing OOP in an ANSI C environment.  It
                attempts to mix Smalltalk like features with the power of
                standard C.  While I have tried to keep the system
                compatible with C++, it is a different approach to OOP than
                that provided by C++.  This package is intended primarily
                for students of OOP and C, although anyone is welcome to use
                it for commercial purposes as they see fit (just send me a
                job application form!).

                     Thank you for examining GCOOPE, please pass it on,
                thank you.

                                         Sincerely,

                                                   Brian L. Price



























                                          36

