[<<Previous Entry]
[^^Up^^]
[Next Entry>>]
[Menu]
[About The Guide]
OOPS - The big easy, or 'who the hell is SELF ??'
Although this is not the tutorial part of the guides, I am sure that a
little introduction into the wonderful world of OOPs can't hurt. If you
are already familiar with this topic, please feel free to skip this
section.
For me, knowing about the underlying mechanism was the key to understand
the concept of OOPs, so I will illuminate the subject from the more
technical and practical side.
The first thing to learn for an OOPs Newbie is to tell the difference
between an Object and a Class, because it is one of the most common errors
to mix them up.
The basical instruments of OOP are classes and messages, not objects.
The Class is a template, or blueprint, for the Objects it creates. It
can build an unlimited number of Objects, which will all be identical
until you initialize them with different data.
Classes are defined with the CREATE CLASS command, and the resulting
Function from that Definition is called the Class Function. It's Name is
the Classname ( like TWINDOW ), and it is a kind of DBCREATE(), but
instead of creating a table it generates Objects, according to the given
specification.
The Object itself looks like an Array; all Variables ( called Instance-
Variables in OOP ) are elements of this Array. Connected to this Object is
a hidden MemoryPart, where special informations are stored, like the
Classname of the Class ( which can be retrieved for every Object by using
the Object:ClassName message ), and the Functions ( called Methods in
OOP ) that are available for this Class.
So let us summarize : Classes are functions that create objects, according
to their definition. Objects send and receive messages that control the
program flow.
What? sending messages?
Yes, it sounds like a post office, but it's far more efficient <g>.
Inside Clipper, every Symbolic text ( called WEED ), like a Function name
or a Message, is associated with a SYMBOL structure.
What happens, when you use
+------------------------------------------+
| oWin:SetFocus() |
+------------------------------------------+
which reads like 'sending the message "SETFOCUS" to the Object oWin' ?
First the message(-string) "SETFOCUS" is translated into a pointer to
the Adress where the Symbol "SETFOCUS" is stored. From now on, our message
is a numeric value, which is much easier to handle than a string.
Next, the SendModule is activated, which retrieves to which class oWin
belongs, and if this class knows the message SETFOCUS at all.
This is done with a 'hashtable' of the class, in which all messages are
listed as a Symbol ( See the function nStrhash() for more informations
on Hashing ).
Once the entry is found, we have the adress of the function or variable
that is associated to the message, and access to other Infos, like the
determined type of instance var, or visibilitiy of the method.
This additional layer of abstraction between the (alias)name of a function
and it's physical adress is the reason why a Function can be named Hj_p(),
but may be called with the more meaningful name o:SetFocus(). In Fact, we
can have one functions SetFocus in every class, without running into
problems with duplicated functions. Or we can have two message names for
one Method, like in :
+------------------------------------------+
| MESSAGE Setfocus METHOD WinFocus_() |
| MESSAGE Activate METHOD WinFocus_() |
+------------------------------------------+
Both messages will call the same function - oops, sorry, Method. With
FiveWin you will notice that nearly every process can be terminated with
the "END" message - the same Message will launch different actions,
according to the object that you send the message to. This is one of the
key features of OOPs, and in our own slang, we call this PolyMorphism.
return to sender
If you have problems with the concept of the send operator ':', then let
me explain it using clipper pseudo code. Imagine that the Object oTable is
an Array with the structure { cMessage, xVar, lIsVar } :
+--------------------------------------------------------------+
| /* Defining the pseudo Class TABLE */ |
| otable:= {{ "AREA" , 0, .T. },; |
| { "ALIAS", "Cust", .T. },; |
| { "OPEN" , {|o|open(o)}, .F. } } |
+--------------------------------------------------------------+
Where Area and Alias are Instance Vars, and Open is a Method of oTable.
For our example, we assume that Clippers great PreProcessor is programmed
to translate 'oTable:area := 1' Into 'Send( otable, "AREA", 1 )'
So then our SendModule SEND() will search the "Object" oTable for the
message "ALIAS", and then replaces the associated Variable with the
argument 1.
If we send the Message "oTable:OPEN" instead, our SendModule will be smart
enough to see that OPEN is a Method ( lIsVar == .F. ), and therefore evals
the associated codeblock. As an argument, it passes the "Object" to the
block and its embedded "Method".
Ok so far ?
Now, inside this method, we don't need to specify oTable. Our Table Object
is always passed to the method invisible as parameter 0 ! To access oTable
from inside the Method, FiveWin generates code like this for every Method:
+-------------------------------------------------+
| /* METHOD DEFINITION */ |
| |
| METHOD <xyz> [CLASS <Classn>] ; |
| => ; |
| FUNCTION <xyz> ; |
| LOCAL self := QSELF() |
| |
+-------------------------------------------------+
Qself retrieves the Object, and stores it to the local var SELF. Because
we use SELF rather often, we trasnlate a double colon to SELF:
+-------------------------------------------------+
| /* ShortCutting SELF */ |
| #xtranslate :: => Self: |
+-------------------------------------------------+
This will save us a lot of typing. You see: inside our Method the Message
::Open() is the same as Self:Open(), which is the same as
QSelf():Open(), its just shorter and faster than the later.
So, if you are still uncomfortable with the 'Method' terminus, just think
of it as a static function that grabs a hidden parameter, and gets called
indirectly by our SendModule. Feel better now ?
But what does this thing called 'Inheritance' mean ?
If we stay with the Array model from above, the Inheritance would simply
mean that our new "Class Access FROM Table" will combine the TABLE class
Array with the new Access-class Array. Now our sendModule finds all
messages from both classes in one object !
The real benefit of this is the abiltiy to 'change' the behaviour ( the
methods ) of the parent class, without actually changing the code of that
that method ( in fact, sometimes even without knowing the code ! )
Imagine that you have 8 heavily used functions, that are interfaced with
each other. Now you have to teach them new tricks, adding 2 functions;
6 of the old functions are working perfectly with little or no change, but
the remaining 2 functions don't, so you have to get 'inbetween' them to
intercept some things and fiddle some IF- ENDIF - DO CASE crutches into
the existing code - normal problems.
And normally you will break your code with the 'little changes', which
results in extensive debugging and new testing.
Now the same thing in OOP: You create a new Class "Newbie", that inherits
from the 8-Method class "Oldie". Newbie has four Methods : two new ones,
and two replacement methods for the Oldie methods that make all the
trouble in the upper example !
How goes this without changing the code ? You just define a Method with
the same (Message)Name, as the original Method that you want to replace !
Because in OOP's functions are called with a Message, rather than by their
function adress, all of the methods of your Newbie class ( also the 'old',
inherited methods ) will now automatically call your new Method.
This does not mean that the original 'overwritten' method is no more
accessible from the Newbie class: Just use the 'SUPER' or 'PARENT' message
to explicietly call the underlying method.
So all you got to do is programm the changes into the Newbie methods, and
then let the Oldie methods do the rest. This is why OOP is often called
"Programming the Exception" : you end up by coding only the Exceptions
into the new class, and build up from the already code. This makes slim
code, and less debugging and retesting, because you don't need to touch
the underlying code.
Got the Idea now ?
If not, don't worry. Go ahead and try it out :'let your fingers float, and
your mind will follow'. OOPs is, technically seen, a very simple thing.
It's more a way of thinking, and its a one way street: Once you have
crossed the magical line, you will never ever want go back to procedural
programming.
Oh yes, one for the way:
If you want to read a real good book about OOPs, I can strongly recommend
'MENTOPOLIS' by Marvin Minsky, ISBN 3-608-93117-1. Don't expect to read
anything about Computers or -Languages in it: Its a pure Analysis of the
human way of thinking and learning, from an OOPs side of view. But it is
one of the most fascinating and exacting book I have ever read.
See Also:
nStrhash
This page created by ng2html v1.05, the Norton guide to HTML conversion utility.
Written by Dave Pearson