TweetFollow Us on Twitter

OOP World
Volume Number:7
Issue Number:9
Column Tag:Developer's Forum

OOP in a non-OOP World

By Steve Sheets, Herndon, VA

[The following article was based on a presentation at the 1990 MacWorld conference in Boston. The speech was given as part of a panel discussion on Object Oriented Programming.]

OOP in a non-OOP World.

“Object Oriented Programming.” These words congure up images of new programming langauges like Smalltalk and C++. Visions of programmers everywhere, throwing out their old compilers and sample code, and starting to program exclusively in an Object Oriented Programming Language are called to mind. Jokes about those who can only program in C or Pascal (“how many Pascal Programmer does it take...”) begin to appear.

Time will tell if the above situations are more spoof than prediction. However, the thinking that inspired them has a very specific fallacy that I would like to address. First, let it be known that I am one of the world’s biggest fans of Object Oriented Programming. I honestly believe that object oriented programming is likely to become the next step in the evolution of programming languages. However, I do not agree that this next step in programming style will be the exclusive domain of the new Object Oriented Programming Langauges. This article intends to show how to make use of object oriented techniques while programming in a non-object-oriented environment. It is possible to use the ideas contained in Object Oriented Programming Languages without using the traditional object oriented constructs like objects, classes, inheritances, or methods. To understand how to go about using the techniques, but not the items, a little history lesson is in order. Even though this lesson is on a slightly different subject, it does have a point.

Back in the long ago, when Computers were first created and introduced to the swarms of eager programmers, the majority of the programming languages were line oriented. Languages like Basic and early versions of Fortran and Cobol usually paralleled Assembly language, where almost every line of code did a specific task and every line was followed by another line of code.

The flow of the program was usually from one line to another. The GOTO or Conditional GOTO statements (or their equivalents) were used to control the flow by branching, but in general, the flow was linear. This technique could cause problems. For one thing, a programmer had to understand practically every single line of the code before he could work with any piece of it. Otherwise, he would never know for sure if the portion of the code he was modifying had an effect on some other line of code. If a person were to try to work with code he had not created, he would likely have to spend a great deal of time studying it before he could work with it.

A second, nastier problem with the linear flow arrangement became apparent as programs became more complex. A simple piece of code might be modified again and again, with different branches at many points in the code. Soon programmers started getting Spaghetti Code, where the code was so complex, and the flow so strange, that no one, perhaps not even the original programmer, could understand how the code worked.

To solve this problem, more Procedural oriented languages were introduced. Languages like Pascal, C, and later expanded versions of line oriented languages were given syntax and commands that allowed a programmer to divide the code into more manageable procedures. People stated talking about the joys of this new Procedural Programming style.

Now a interesting thing started happening. Programmers who used the procedural languages, and who learned the joy of procedural programming, would sometimes still have to program using the older languages. However, they had gotten used to the advantages of the newer languages. So they added some of those new ideas to their programs, even though they were using the old languages. They wrote the programs so that they had separate subroutines and functions. Even Basic could be written in this procedural style, once the programmer understood the concept.

Notice that just because a program is written in a good procedural base programming language, it does not necessarily follow that the program is good code. Some of the worst examples of spaghetti code have been written in the so called higher level languages. These languages just made it easier to learn a new idea, like procedural programming. The languages helped to teach programmers good programming habits. Once the style was learned, it was not necessary to use the new language or features in order to implement the technique.

That’s the end of the history lesson. Now, to come back to the present; nearly everyone has been exclaiming the joys of these new Object Oriented Programming Languages. Notice any possible parallel to my history lesson? Just like those who years ago promoted Procedural Programming, they are right. There are many benefits to using object oriented programming. This new type of programming will allow you to code better. But you do not have to use Smalltalk or C++ or Object Pascal in order to implement the benefits of object oriented programming.

Many programmers would probably like to use an object oriented approach, or at least they would be interested in learning about it. However, these people may be unable, for perfectly valid reasons, to start using an Object Oriented Programming Language today. Many may have to work in a language specified by their company, or one that is specified by their job contract. Some may have to work on a computer that does not have a Object Oriented Programming Language. Or some might have to program with co-workers who have not yet “seen the light” of Object Oriented Programming. And many may have already invested a large amount of time and energy a piece of non-object-oriented code, resources they might not have to reinvest in order to convert over to an object oriented approach.

That last reason was the one that kept me from using an Object Oriented Programming Language on my project, America Online. There was already an Alpha version of the code written in Think Pascal, without Object extensions. Neither MacApp or any other Object Oriented Programming Language was an option for America Online when I came onto the project. While there is almost nothing left of the original Alpha code in the current version of America Online, there never was a time when we could take the time that would have been needed to convert the entire code to use Object Pascal extensions or MacApp. So instead, what we did was to look at various parts of America Online and decided what we could improve using what we had learned about America Online.

Since I’m going to refer frequently to my project in this article, perhaps I’d better give you a little information about it. For those who are not familiar with it, America Online is a telecommunication service which connects our host mainframe to personal computers using proprietary protocols and software. In my case, we are using Macintoshes connected over a serial modem line. Using a low-level protocol, packets of data are transferred, error free, from the host to the Mac or visa versa. When a data packet comes in, the first few bytes of data designate what task that packet is intended to preform. A group of tasks related to a specific online function is called an “Engine”. Engines include the Form Engine (to create the windows), the Chat engine (to handle online chat rooms), Async Engine (to handle other actions), File transfer engine (to handle uploads & downloads), the LogOn Engine (to handle the log on process), and the LogOff engine (which handles the log off process).

When a packet of information comes in from the Host, America Online has to decide which engine handles that packet. Originally, America Online used procedural styles. Each Engine had a Packet Handling routine that decided whether or not that packet was handled by that engine. If it did, the packet was handled and the function returned TRUE. If it did not, the function did nothing but return FALSE. Every engine accessed the global variable space of the program in order to store states.

The original code segment that parsed a packet looked something like this.

{1}

FUNCTION Form_Engine(thePacket:TDataType);   FORWARD;
FUNCTION Chat_Engine(thePacket:TDataType);   FORWARD;
FUNCTION File_Engine(thePacket:TDataType);   FORWARD;
FUNCTION LogOn_Engine(thePacket:TDataType);  FORWARD;
FUNCTION LogOff_Engine(thePacket:TDataType); FORWARD;

PROCEDURE ParsePacket(thePacket:TDataType);
BEGIN
 IF NOT Form_Engine(thePacket) THEN
 IF NOT Chat_Engine(thePacket) THEN
 IF NOT Async_Engine(thePacket) THEN
 IF NOT File_Engine(thePacket) THEN
 IF NOT LogOn_Engine(thePacket) THEN
 IF NOT LogOff_Engine(thePacket) THEN
 ;
END;

This piece of code just simply bothered me. It looks cumbersome and is difficult to manipulate. Each engine is always called, no matter whether or not the engine is on. There is no sense of which packet might effect what global data. Adding more engines to the code made the code segment even more awkward.

So I decided to apply a few of the techniques that I learned in Object Oriented Programming classes. I created some new data structures. These new structures included a new record type (TEngineRec), a pointer to this record (TEnginePtr) and a handle to the record (TEngineHdl). TEngineRec consisted of a TEngineHdl, a normal data Handle and a ProcPtr.

{2}

TYPE  TEngineRec = RECORD
 EngineData: Handle;
 EngineProc: ProcPtr;
 NextEngine: TEngineHdl;
 END;
 TEnginePtr = ^TEngineRec;
 TEngineHdl = ^TEnginePtr;

For those unfamiliar with ProcPtr, it is a pointer to an actual procedure or function in memory. Depending on your language or development system, it allows the procedure it indicates to be invoked. To do the actual invoking of this procedure, I defined an Inline call that places the correct parameters on the stack and then jumps to the procedure the pointer is aimed at and executes it.

In order to make this code work, I also created one global variable, GEngineList, a TEngineHdl type.

VARGEngineList: TEngineHdl;

Obviously the idea was to try to create a linked list of Engines. GEngineList points to the first Engine in the list, and each engine points to the next one. A set of routines to add and subtract Engines to the the list was also needed. I therefore declare the following call.

{3}

FUNCTION AddEngine(theProc:ProcPtr;theData:Handle):TEngineHdl;
FORWARD;

PROCEDURE RemoveEngine(theEngine:TEngineHdl);
FORWARD;

These routines are uses to add and remove an engine from our list of active engines. The AddEngine call would be invoked like this:

{4}

VARtheFormEngine:TEngineHdl;
 theFormData:Handle;

theFormData :=...{Code to initilize data}...

theEngine:=AddEngine(@Form_Engine,theFormData);

Notice that when an engine was added, the pointer was passed to the Engine’s Packet_Handling routine. That routine will be executed later, when a packet comes in.

Now, let us revisit the original piece of code. The original code will pass a packet to all engines until it finds one that wants the packet. The new code only passes packets to engines that have been installed.

{5}

PROCEDURE New_ParsePacket(thePacket:TDataType);
VARHandled:BOOLEAN;
 theList:TEngineHdl;
BEGIN
 Handled:=FALSE;
 theList :=GEngineList;
 WHILE (NOT Handled) and (theList<>NIL) DO BEGIN
   IF Call_To_Proc(thePacket,theList^^.theData, theList^^.theProc)
 THEN Handled:=TRUE
 ELSE theList:=theList^^.NextEngine
 END;
END;

Call_To_Proc is a glue routine that actually jumps to the Procedure pointed to at theList^^.theProc with thePacket and theList^^.theData as parameters.

Now, imagine what happens during a normal logon sequence. As a user first goes online, a LogOn Engine is created. Once the person is completely online, the LogOn Engine is removed and it’s handle and data handle are deallocated from memory. Then the Forms Engine and the Async engines are added to the Engine List. These Engines normally run for the life of an online session to handle most normal forms and asynchronous events.

At some point the user might decide to go to a Chat room. The Chat engine is added when, and only when, the user enters a Chat room. When he leaves the Chat room, the engine is removed. The same can happen to a File transfer engine.

Some of the advantages of this approach become apparent if you consider how we can use the new code to create new situations. Since the data for each engine is completely contained in that engines data handle, the protocol could be changed so that a user can be in more than one chat room at the same time. This would mean a chat room packet would have to have some information in it to determine whether it pertained to room “A” or room “B”, but that information would only require a couple of bytes of data and would be easy to include.

There is no reason why File transfer, or any other engine that could be conceived, could not be added and invoked any number of times, at any point in an online session. This gives us an amazingly powerful online asynchronous environment. What we are really seeing is an example of the Object Oriented concept of encapsulation of data and the concept of instance of an object.

More than one instance can easily be added to the code at any time. Until an instance is added, additional memory need not be allocated. If an engine is changed, or even if a new one is added, only routines related to the new engine need to be added. The parser code segment used to send a packet to the correct engine is never changed.

I have always considered Data Encapsulation and Instance of objects to be two of the three most important ideas associated with Object Oriented Programming. The third important idea is that of Inheritance. And this function of an Object Oriented Programming Language can be adopted to non-Object Oriented Programming Languages, too.

Actually we are already halfway there in our example. ProcPtrs can be manipulated so that certain data structures have pointers to some procedures, while other instances use other procedures. This simulates the idea that a method can be overridden or inherited. To see this more easily, lets consider another example that has ProcPtrs.

America Online has a very complete Forms engine that allows us to create almost any form using packets sent from the host. Each form packet has information describing windows and different fields on these windows. Different field types that can be on a window might include buttons, icons, pictures, non-editable text, editable text, lists, and so on. All the fields have certain tasks that they have to be able to perform. For example, each field must be able to be drawn, it must be able to handle a mousedown in it’s area, it must be able to be hilited, it must be able to handle a keystroke, it must be able to invert itself and it must have an action associated with it. Following this idea, a field data structure might look like this.

{6}

FieldRec = RECORD
  fArea : Rect;
  fActionNum : INTEGER;
  fText: Str255;
  fData : Handle;
  pMouseDown,pUpdate,pActivate,pHilite,pKeydown,pAction : ProcPtr;
 END;

FieldRec = ^ FieldPtr;
FieldHdl = ^FieldPtr;

Besides the data, a number of ProcPtrs are declared, one for each major task. Some of the tasks might be do nothing tasks. For instance, a non-editable text field would ignore keystrokes, or a picture would not need to have an action associated with it. Others are more specific for the given field type (the keystroke routine for an editable text field).

For example, when the window needs to be updated, the code might find the field list for that window. Then it would one by one cycle through each of the fields, invoking the draw command so that that portion of the window is drawn. That code would look something like the following example. Notice if the ProcPtr is nil, that means there is a do-nothing task, and it should be skipped.

{7}

PROCEDURE UpdateDisplay(theDisplay:DisplayHdl);
VAR theField:FieldHdl;
BEGIN
 theField:=theDisplay^^.FirstField;
 WHILE (theField<>NIL) DO BEGIN
   IF theField^^.pUpdate<>NIL
   THEN Invoke_Update(theField,theField^^.pUpdate);
   theField:=theField^^.NextField;
 END;
END;

If a mousedown occurs, a similar scan is done. In that case, each field is checked to see if the mousedown occurs in it. The Mousedown ProcPtr will only be invoked if the mousedown has occurred in the relevant field. Notice that no matter which type of field is used, these pieces of code will never change.

Somewhere in the code, there will be a segment of code that creates these fields; this procedure is called New_Field. Each kind of field will have its own declaration section in the procedure. For example, a picture might look like this.

{8}

FUNCTION New_Field(theKind:INTEGER;
 theBox:Rect;
 theID:INTEGER):FieldHdl;
VAR theField:FieldHdl;
BEGIN
 ...
 CASE Kind OF
 ...
 kPicture: BEGIN
   theField^^.fArea:=theBox;
   theField^^.fData:=GetPicture(theID);
   ...
   theField^^.pUpdate:=@Draw_Pic_Field;
   theField^^.pHilite:=@Invert_Area_Field;
   theField^^.pAction:=NIL;
 ....
 END;
 OTHERWISE
 New_Field:=theField;
END;

You can see that this kind field basically does nothing but draw itself. A more interesting kind of field might be a clickable Icon field.

{9}

 kClickIcon: BEGIN
   theField^^.fArea:=theBox;
   theField^^.fAction:=theAction;
   theField^^.fData:=GetIcon(theID);
   ...
   theField^^.pUpdate:=@Draw_Icon_Field;
   theField^^.pHilite:=@Invert_Icon_Mask_Field;
   theField^^.pAction:=Do_Action_Number;
   theField^^.pMouseDown:=@Track_Invert;
   ....
 END;

This type of field has it’s own draw and invert calls. It also uses the Track_Invert call in order to handle a mousedown. That call keeps track of whether or not the mouse is inside the field area. It invokes the Invert ProcPtr repeatedly to hilite or unhilite the field depending on if the mouse is in or out of the area. If the user releases the button while the mouse is over the field, that call invokes the Action ProcPtr. The action ProcPtr is the most generic one, the Do_Action_Number procedure which does an action defined in the ActionNumber field.

If an entirely new kind of field needs to be created, say for example a clickable Picture, some of the previously defined routines could be used (inherited) to define this kind of object. This code would be added to the new field.

{10}

 kClickPict: BEGIN
 theField^^.fArea:=theBox;
 theField^^.fAction:=theAction;
 theField^^.fData:=GetPicture(theID);
 ...
 theField^^.pUpdate:=@Draw_Pic_Field;
 theField^^.pHilite:=@Invert_Area_Field;
 theField^^.pAction:=Do_Action_Number;
 theField^^.pMouseDown:=@Track_Invert;
 ....
 END;

We have created a new type of field, with it’s own specific appearance and function, without adding any new code except for the creation routine. Even if we had to create a new field with a new special task, (such as a new way to handle drawing,) only a single new procedure would need to be written (in this case, Draw_Bitmap_Icon). We can use the old procedures/tasks for the rest of the new field.

Notice that this Clickable PICT field is related to a non-Clickable PICT field. These fields don’t quite function as a superclass and a subclass, but there is a relationship involved. This might not be true inheritance, but it sure does make it easier to create new fields when they are needed.

Inheritance, instancing of objects and data encapsulation are possibly the three most important ideas in object oriented programming, and they have all been simulated in a non-object-oriented procedural language. And I would like to add that this this is not merely sample code that is never used in a real-world application. These three ideas are used over and over again inside of America Online.

The code would have never been designed the way it was if I had not aware of the object oriented concepts and had not seen them used in a object oriented world. America Online is a better product because of the object oriented lessons learned. The code is more flexible, easier to work with and more powerful. Even if a programmer is never to use MacApp in a major project, or he is never to use an Object Oriented Programming Language in a job, the project or job he is working on, the code he creates may be better if he uses the object oriented concepts he learns.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.