[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]

 My understanding of OOP revolves around three principles:

  ENCAPSULATION:  All data-Types, Procedures, Functions are placed
                  within a new Type of wrapper called an Object.

                  This new wrapper is very simillar to a standard
                  Record structure, except that it also contains
                  the routines that will act on the data-Types
                  within the Object.

                  The Object-oriented style of Programming requires
                  that you should ONLY use the routines within the
                  Object to modify/retrieve each Object's data-Types.
                  (ie: Don't access the Variables directly.)

      Structured Style                 OOP Style
      ================                 =========
      MyRecord = Record                MyObject = Object
                   1st Variable;                    1st Variable;
                   2nd Variable;                    2nd Variable;
                   3rd Variable                     3rd Variable;
                 end;                               Procedure One;
                                                    Procedure Two;
                                                    Function One;
                                                    Function Two;

     inHERITANCE: This gives you the ability to make a new Object by
                  cloning an old Object. The new Object will contain
                  all the abilities of the old Object.
                  (ie: Variables, Procedures/Functions).

                   You can add additional abilities to this new Object,
                   or replace old ones.

                               |  New Object  |
                               |  +--------+  |
                               |  |  Old   |  |
                               |  | Object |  |
                               |  +--------+  |

                   With Inheritance, you don't have to go back and
                   re-Write old routines to modify them into new
                   ones. Instead, simply clone the old Object and
                   add or replace Variables/Procedures/Functions.

                   This makes the whole process of rewriting/modifying
                   a Program MUCH faster/easier. Also there is less
                   chance of creating new bugs from your old bug-free

  POLYMorPHISM:    The name Sounds intimidating, but the concept is

                   Polymorphism allows one Procedure/Function to
                   act differently between one Object and all its
                   descendants. (Clones)

                   These Type of "polymorphic" Procedures/Functions
                   know which Object they are working on, and act
                   accordingly. For example:

                   Say you've created an Object (Object-1) that
                   contains a Procedure called DrawWindow, to draw
                   the main screen of a Program.

                   DrawWindow relies on another Procedure SetBorder
                   within Object-1, to set the borders used in the
                   main screen.

                   Now you clone Object-2 from Object-1.

                   You want to use Object-2 to handle pop-up Windows,
                   but you want the pop-ups to have a different border

                  if you call the DrawWindow Procedure that Object-2
                   inherited from Object-1, you'll end up With a Window
                   With the wrong border-style.

                   to get around this you could change the SetBorder
                   Procedure to a "Virtual" Procedure, and add a
                   second identically named "Virtual" Procedure
                   (SetBorder) within Object-2.

                   A "Virtual" Procedure relies on a "Virtual Table"
                   (Which is basicly a Chart to indicate which
                    "Virtual" routine belongs to which Object)
                   to, indicate which version of the identically
                   named Procedures should be used within different

                   So within Object-1, the DrawWindow routine will
                   use the SetBorder Procedure within Object-1.

                   Within Object-2, the inherited DrawWindow routine
                   will use the other SetBorder Procedure that belongs
                   to Object-2.

                   This works because the "Virtual Table" tells the
                   DrawWindow routine which SetBorder Procedure to
                   use For each different Object.

                   So a call to the SetBorder Procedure now acts
                   differently, depending on which Object called it.
                   This is "polymorphism" in action.

  OOP LANGUAGE LinGO: The following are some of the proper names For
                      OOP syntax.

     Structured Programming       OOP Programming
     ======================       ===============
      Variables                   Instances
      Procedures/Functions        Methods
      Types                       Classes
      Records                     Objects

> i have a parent Object defined With Procedure a and b.
> i have a child Object With Procedure a, b and c.

> when i declare say john being a child, i can use a, b, or c With no
> problem.  when i declare john as being a parent, i can use a or b.

> if i declare john as being a parent and initialise it with
> new (childPTR,init) it seems i have access to the parent fields

After reading twice, I understand you mean Object classes dealing With humans,
not trees (happen to have parents & childs too).

> parent a,b,c,d,e,f
> parent a,b
> child a,b,c
> child2 a,b,d
> child3 a,b,e,f
 (redefine a, b For childs as Far as they differ from parent a,b)

Next example could be offensive For christians, atheists and media-people.

  TParent = Object    { opt. (tObject) For Stream storage }
    Name : String;
    Constructor Init(AName: String);
    Procedure Pray;             { your A,
                                  they all do it the same way }
    Procedure Decease; Virtual; { your B, Virtual, some instances
                                  behave different (Heaven/Hell) }
    Destructor Done; Virtual;
  TChild1 = Object(TParent)
    Disciples : Byte;
    Constructor Init(AName: String; DiscipleCount: Byte);
    { do not override Decease } { calling it will result in a
                                  call to TParent.Decease }
    Procedure Resurrection;     { your C }
  TChild2 = Object(TParent)
    BulletstoGo : LongInt;
    Constructor Init(DisciplesCount: Byte; Ammo: LongInt);
    Procedure Decease; Virtual;         { override }
    Procedure Phone(Who: Caller);  { your D }

  Constructor TParent.Init(AName: String);
    Name := AName;
  Destructor TParent.Done;
  Procedure TParent.Pray;
  Procedure TParent.Decease;

  Constructor TChild1.Init(AName: String; DiscipleCount: Byte);
    inherited Init(AName);
    Disciples := DiscipleCount;
  Procedure TChild1.Resurrection;

  Constructor TChild2.Init(AName: String;
                           DiscipleCount: Byte; Ammo: LongInt);
    inherited Init(DiscipleCount);
    BulletstoGo := Ammo;
  Procedure TChild2.Decease;
  Procedure TChild2.Phone(Who: Caller);
    Case Who of
      AFT   : Ventriloquize;
      Media : Say('Burp');
In the next fragment all three Types of instances are put into a collection.
  Christians : PCollection;

  Christians := New(PCollection, Init(2,1));
  With Christians^ do begin
    Insert(PParent, Init('Mary'));
    Insert(PParent, Init('John'));
    Insert(PChild1, Init('Jesus', 12));
    Insert(PChild2, Init('Koresh', 80, 1000000));
Now you can have all instances pray ...
  Procedure DoPray(Item: Pointer); Far;
    { unTyped Pointers cannot have method tables. The PParent
      Typecast Forces a lookup of Pray in the method table.
      All instances With a TParent ancestor will point to
      the same (non-Virtual) method }
  { being sure all Items in Christians are derived from TParent }
and because all mortals will die...
  Procedure endVisittoEarth(Item: Pointer); Far;
    { Decease is a Virtual method. The offset of a location in
      the VMT With the address of a Virtual method is determined by
      the Compiler. At run-time, For each Type of instance 1 VMT
      will be created, it's method-fields filled With the
      appropriate addresses to call.
      Each instance of an Object derived from TParent will have the
      address of it's VMT at the same location. Calling a Virtual
      method results in
         1) retrieving that VMT address at a known offset in
            the instance's data structure
         2) calling a Virtual method at a known offset in the
            VMT found in 1)
      ThereFor mr. Koresh will go to hell: PChild2's VMT contains
      at the offset For Decease the address of the overridden
      method. Mr. Jesus, a PChild1 instance, simply inherits the
      address of PParent's Decease method at that offset in the
      VMT.                                                        }

->   ...I've no problem posting my code, but I'm still not Really happy
->   With it's present Implementation. I also don't think that dynamic
->   Array Objects are very good examples of OOP. (For example, what
->   do extend the dynamic-Array Object into, via inheiritance???)
->   ...Something more like a generic "Menu" or "Line-Editor" Object
->   might be a better example.

Well I don't know exactly what you are trying to do With your dynamic
Array but it can be OOP'ed.  Linked lists are a prime example (I hope
this is close)  By using OOP to Write link lists you can come up with
Objects such as:

    ListPtr = ^List;
    NodePtr = ^ListNode;

    List (Object)
      TNode   : Pointer;  {Pointer to the top Record}
      BNode   : Pointer;  {Pointer ro the bottom Record}
      CurNode : Pointer;  {Current Pointer}

    Constructor Init;             {Initializes List Object}
    Destructor  Done;  Virtual;   {Destroys the list and all its nodes}

    Function top    (Var Node : ListNode) : NodePtr;
    Function Bottom (Var Node : ListNode) : NodePtr;
    Function Next   (Var Node : ListNode) : NodePtr;
    Function Prev   (Var Node : ListNode) : NodePtr;
    Function Current(Var Node : ListNode) : NodePtr;

    Procedure AttachBeFore (Var Node : ListNode);
    Procedure AttachAfter  (Var Node : ListNode);
    Procedure Detach       (Var NodePtr : Pointer);


  ListNode = Object;
    Prev : NodePtr;
    Next : NodePtr;

  Constructor Init;
  Destructor  Done;  Virtual;


The list Object is just that.  It has the basic operations you would do
with a list.  You can have more than one list but only one set of
methods will be linked in.  The List node Dosn't have much other than
the Pointers to link them into a list and an Init, done methods.  Sounds
like a ton of work just to implement a list but there is so much you can
do easely With OOP that you would have a hard time doing conventionally.
One example, because the ListNode's Done Destructor is Virtual the Done
of the list can accually tranvirs the list and destroy all Objects in
the list.  One list can accually contain Objects that are not the
same!!!  Yep it sure can.  As long as an Object is dirived from ListNode
the list can handel it.  Try to do that using conventional methods!!

I'm assuming that your dynamic Array will do something similar which is
why I suggested it.  A Menu and Line editor Objects are High level
Objects that should be based on smaller Objects.  I'd assume that a line
editor would be a Complex list of Strings so the list and ListNode
Objects would need to be built.  See what I mean???

then you get into Abstract Objects.  These are Objects that define
common methods For its decendants but do not accually have any code to
suport them.  This way you have set up a standard set of routines that
all decendants would have and Programs could be written using them.  THe
results of which would be a Program that could handel any Object based
on the abstract.

-> RM>I have mixed feeling on this. I see OOP and Object as tools For a
-> RM>Program to manipulate.
-> RM>  IE: File Objects, Screen Objects, ect then bind them together
-> RM>      in a Program using conventional style coding.
->   ...to my understanding of the OOP style of Programming, this would
->   be a "NO-NO".

OK well With the exception of TApplication Object in Turbo Vision a
Program is a speciaized code that more than likely can't be of any use
For decendants.  That was my reasioning at least.  and the Tapp Object
isn't a Program eather.  YOu have to over ride a ton of methods to get
it to do anything.
Unit OpFile;  {*******   Capture this For future referance   *******}



DateTimeRec = Record
              {Define the fields you want For date and time routines}

AbstractFile = Object

  Function  Open : Boolean;                                   Virtual;
    {Opens the File in the requested mode base on internal Variables }
    {Returns True if sucessfull                                      }

  Procedure Close;                                            Virtual;
    {Flush all buffers and close the File                            }

  Function  Exists : Boolean;                                 Virtual;
    {Returns True is the File exists                                 }

  Function  Create : Boolean;                                 Virtual;
    {Will create the File or overWrite it if it already exists       }

  Procedure Delete;                                           Virtual;
    {Will delete the File.                                           }

  Function  Rename : Boolean;                                 Virtual;
    {Will rename the File returns True if successfull                }

  Function  Size : LongInt;                                   Virtual;
    {Returns the size of the File.                                   }

  Procedure Flush;                                            Virtual;
    {Will flush the buffers without closing the File.                }

  Function  Lock : Boolean;                                   Virtual;
    {Will attempt to lock the File in a network enviroment, returns  }
    {True if sucessfull                                              }

  Procedure Unlock;                                           Virtual;
    {Will unlock the File in a network enviroment                    }

  Function  Copy (PathName : String) : Boolean;               Virtual;
    {Will copy its self to another File, returns True is successfull.}

  Function  GetDateTime (Var DT : DateTimeRec) : Boolean;     Virtual;
    {Will get the File date/time stamp.                              }

  Function  SetDateTime (Var DT : DateTimeRec) : Boolean;     Virtual;
    {Will set the File date stamp.                                   }

  Function  GetAttr : Byte;                                   Virtual;
    {Will get the File attributes.                                   }

  Function  SetAttr (Atr : Byte) : Boolean;                   Virtual;
    {Will set a File's attributes.                                   }

end; {of AbstractFile Object}


  Procedure Abstract;    {Cause a run time error of 211}
    Runerror (211);

  Function  AbstractFile.Open : Boolean;

  Procedure AbstractFile.Close;

  Function  AbstractFile.Exists : Boolean;

  Function  AbstractFile.Create : Boolean;

  Procedure AbstractFile.Delete;

  Function  AbstractFile.Rename : Boolean;

Ok theres a few things we have to talk about here.

1.  This is an ABSTRACT Object.  It only defines a common set of
routines that its decendants will have.

2.  notice the Procedure Abstract.  It will generate a runtime error
211.  This is not defined by TP.  Every Method of an Object has to do
somthing.  if we just did nothing we could launch our Program into
space.  By having all methods call Abstract it will error out the
Program and you will know that you have called and abstract method.

3.  I'm sure some may question why some are Procedures and some are
Functions ie Open is a Function and close is a Boolean.   What I based
them on is if an error check a mandatory it will be a Function Boolean;
This way loops will be clean.  Open in a network Open will require a
check because it may be locked.  Which brings up point 4.

4.  We are not even finished With this Object yet.  We still have to
define a standard error reporting / checking methods and also lock loop
control methods.  not to mention some kind of common data and methods to
manipulate that data.  Moving to point 5.

5.  Where does it end???  Well we hvae added quite a few Virtual methods
While thsi is not bad it does have a negative side.  All Virtual methods
will be linked in to the final EXE weather it is used or not.  There are
valid reasions For this but you don't want to make everything Virtual if
it Dosn't have to be.  My thinking is this.  if it should be a standard
routine For all decendants then it should be Virtual.  if required
methods call a method then why not make it Virtual (this will become
more apparent in network methods and expanding this Object)

Now personally I get a feeling that the DateTime and Attr methods
shouldnn't be there or at least not Virtual as the vast majority of
Programs will not need them and its pushing the limits of Operating
system spisific methods.  SO it will probly be a Dos only Object.  (Yes
there are others that have this but I think its over kill)  The same
goes For the copy and rename methods so I would lean to removing them
from this Object and define them in decendants.

So what do you think we need to have For error checking / reporting
methods???  Do you think we could use more / different methods???

 DW> I am trying to teach myself about Object orientated Programming and
 DW> about 'inheritence'. This is my code using Records.

The idea of Object oriented Programing is what is refered to as
encapsulation.  Your data and the Functions that manipulate it are
grouped together.  As an example, in a traditional Program, a linked
list would look something like:

  Linked_List =
      Data : Integer; {Some data}
      Next : ^Linked_List; {Next data}
      Prev : ^Linked_List; {Prev data}

then you would have a whole slew of Functions that took Linked_List as a
parameter.  Under OOP, it would look more like

  Linked_List =
      Data : Integer;
      Next : ^Linked_List;
      Prev : ^Linked_List;

      Constructor Init();   {Initializes Linked_List}
      Destructor  DeInit(); {Deinitializes Linked_List}
      Procedure AddItem(aData : Integer);
      Procedure GetItem(Var aData : Integer);

then, to add an item to a particular list, the code would look like:

This is easier to understand.  An easy way to think about this is that
an Object is an entity sitting out there.  You tell it what you want to
do, instead of calling a Function you can't identify.  Inheritance
allows you to make a linked list that holds a different Type, but Uses
the same Interface funtions.  More importantly, using the same method
and Pointers, you could have both Types in the same list, depending on
how you implemented it.

It helps debugging time, because if you wanted to add a Walk_List
Function, you could add it and get it working For the parent Object, and
(since the mechanics of it would be the same For ANY Linked List), you
could Write it once and use it without problems.  That is a clear
advantage.  Other Uses include:

(For a door Type Program) and Input/Output Object that serves as a base
For a console Object and a modem Object, and thusly allows you to treat
the two as the same device, allowing you to easily use both.

(For a BBS Message base kit) a Generic Message Object that serves as a
base For a set of Objects, each of which implements a different BBS'
data structures.  Using this kit, a Program could send a message to any
of the BBSes just by knowing the core Object's mechanics.

(For Windows) a Generic Object represents a Generic Window.  By
inheritance, you inherit the Functionality of the original Window.  By
creating an Object derived from the generic Window, you can add
additional Functionality, without having to first Write routines to
mirror existing Functionality.

(For Sound) a Generic Object represents a generic Sound device.
Specific child Object translate basic commands (note on, note off, etc)
to device specific commands.  Again, the Program doesn't have to know
whether there is a PC speaker or an Adlib or a SoundBlaster--all it has
to know is that it calls note_on to start a note and note_off to end a

There are thousands on thousands of other examples.  if you read through
the turbo guides to turbovision or to Object oriented Programming, they
will help you understand.  Also, a good book on Object oriented
Programming doesn't hurt ;>.

> Now, the questions:
> 1. How do I discretly get the Lat & Long into separate
> Collections? In other Words (psuedocode):

No need For seperate collections, put all the inFormation in a Single

> Any hints would be appreciated. Thanks!

I'll not give any help With parsing the Text File, there will probably be a ton
of advice there, but here is a little Program that I threw together (and
tested) that will list the inFormation and present the additional data.
Have fun With it.

Program Test;
Uses Objects,dialogs,app,drivers,views,menus,msgbox;

  (*Define the Data Element Type*)
  Data = Record
           Location : PString;
           Long,Lat : Real;
  PData = ^Data;

  (*Define a colection of the data elements*)
  DataCol = Object(TCollection)
              Procedure FreeItem(Item:Pointer); Virtual;
  PDC     =^DataCol;

  (*Define a list to display the collection*)
  DataList = Object(TListBox)
               Function GetText(item:Integer;maxlen:Integer):String; Virtual;
               Destructor done; Virtual;
  PDL = ^DataList;

  (*Define a dialog to display the list *)
  DataDlg = Object(TDialog)
              Pc : PDC;
              Pl : PDL;
              Ps : PScrollBar;
              Constructor Init(Var bounds:Trect;Atitle:TTitleStr);
              Procedure HandleEvent(Var Event:TEvent); Virtual;
  PDD     = ^DataDlg;

  CmCo = 100;
  CmGo = 101;

Procedure DataCol.FreeItem(Item:Pointer);

Function DataList.GetText(item:Integer;maxlen:Integer):String;
     GetText := PString(PData(List^.At(item))^.Location)^;

Destructor DataList.Done;

Constructor DataDLG.Init(Var bounds:Trect;Atitle:TTitleStr);
   r  : trect;
   pd : pdata;
     geTextent(r); r.grow(-1,-1); r.a.x := r.b.x - 1; dec(r.b.y);
     new(ps,init(r)); insert(ps);

     geTextent(r); r.grow(-1,-1); dec(r.b.x); dec(r.b.y);
     new(pl,init(r,1,ps)); insert(pl);

     geTextent(r); r.grow(-1,-1); r.a.y := r.b.y - 1;
                newstatuskey('~[Esc]~ Quit ',kbesc,CmGo,
                newstatuskey('   ~[Alt-C]~ Co-ordinates ',kbaltc,CmCo,

     With pc^ do        (*parse your File and fill the*)
       begin            (*collection here             *)
         pd^.location := newstr('Port Arthur, Texas');
         pd^.long := 29.875; pd^.lat  := 93.9375;
         pd^.location := newstr('Port-au-Prince, Haiti');
         pd^.long := 18.53; pd^.lat  := 72.33;
         pd^.location := newstr('Roswell, New Mexico');
         pd^.long := 33.44118; pd^.lat  := 104.5643;

Procedure DataDlg.HandleEvent(Var Event:TEvent);
    los,las : String;
     if Event.What = EvCommand then
        Case Event.Command of
          CmGo : endModal(Event.Command);
          CmCo : begin
             #3+PString(PData(Pl^.List^.At(Pl^.Focused))^.Location)^ +
             #13+#3+'Longitude : '+los+#13+#3+'Latitude  : '+las,

Type  (*the application layer *)
  myapp = Object(Tapplication)
            Procedure run; Virtual;

Procedure myapp.run;
   Var r:trect;
     new(p,init(r,'Dialog by ken burrows'));
     if p <> nil then



>   I am having a problem.  I would like to Write an editor.  The
> problem is I dont understand a thing about Pointers (which everyone
> seems to use For editors).

   I'm certainly no TP expert, but I might be able to help out With the
Pointers.  Pointers are just special 4-Byte Variables that contain (
point to) a specific position in memory.  You can also make a Pointer
act like the thing to which it is pointing is a particular Type of
Variable (Byte, String, etc).  Unlike normal Var Variables, however, these
Variables are what's referred to as Virtual -- they aren't fixed in the
.EXE code like Var Vars, so you can have as many of them as you like,
within memory Constraints.  Each is created when needed using the GetMem
statement.  This statement makes a request For some more memory to be
used in the heap (all left-over memory when the Program loads usually).

What you need in a editor is to be able to somehow link the Strings
that make up the document into what's called a list (first line, next,
... , last line).  The easiest way to visualize this is a bunch of people
in a line holding hands, each hand being a Pointer.  The hand is not the
entire person, it just connects to the next one.  So, what you do is
use a Record that contains one String For one line of Text, a Pointer to
the previous line of Text in the document, and a Pointer to the next line
in the document.  A Record like this should do it:
    {+------------------------- Usually used in starting a Type of Pointer}
    {|+------------------------ Points to a String in the document        }
    {||            +----------- This is usedto mean that PStringItem is   }
     ||            |            to be a Pointer pointing to a Record      }
     ||            |            known as TStringItem                      }
    {vv            v
Type PStringItem = ^TStringItem;
     TStringItem : Record
        LineOText : String [160]; {Double the screen width should do it}
        NextLine  : PStringItem;  {Points to the next line in memory}
        PrevLine  : PStringItem;  {Points to the previous line in memory}

In your editor main Program, use

Var FirstLine, LastLine, StartLine, CurrLine : PStringItem;

to create Varibles giving you `bookmarks' to the first line in the
File, last in the File, the one the cursor is on, and the one that
starts the screen.  All of these will change.

to create the first line in the document, use:

GetMem (FirstLine, Sizeof (TStringItem)); {get memory enough For one line}
CurrLine := FirstLine;   {of course, only one line in the doc so Far!}
LastLine := FirstLine;
StartLine := FirstLine;
FirstLine^.NextLine := nil; {nil means no particular place-- there's no}
FirstLine^.PrevLine := nil; {line beFore of after FirstLine yet        }

Now the Variable FirstLine will contain the address of the newly created
Variable.  to address that Variable, use the carrot (^), like this:

FirstLine^.LineOText := 'Hello World!');

to make a new line in the list just get more memory For another line:

GetMem (LastLine^.NextLine, Sizeof (TStringItem));
LastLine := LastLine^.NextLine;

This will get more memory and set the last line in the File's
next line Pointer to the new String, then make the new String the
last line.

Deleting a line is almost as simple.  You use the FreeMem Procedure
to release the memory used by a Variable.  if it's in the middle of the
list, just set the to-be-deleted's next line's previous line to the
to-be deleted's previous line, and the previous line's next to the one
after the one to be deleted, essentially removing it from the list and
then tieing the peices back together.  You can then kill off the memory
used by that line.

{Delete current line}
if CurrLine^.NextLine <> nil then {there's a line after this one}
   CurrLine^.NextLine^.PrevLine := CurrLine^.PrevLine;
if CurrLine^.PrevLine <> nil then {there's a line beFore this one}
   CurrLine^.PrevLine^.NextLine := CurrLine^.NextLine;
FreeMem (CurrLine, Sizeof (TStringItem));

to insert a line, just do about the opposite.

if you don't understand, I won't blame you, I'm half asleep anyway...
but I hoe it clears some of the fog.  if the manual isn't helpful
enough now, try tom Swan's _Mastering Turbo Pascal_, an excellent

[Back to OOP SWAG index]  [Back to Main SWAG index]  [Original]