A Simple Explanation of OOP
Object-oriented programming (or OOP) is one of the most poorly understood things in computer programming. It is especially challenging for beginners who seem unable to apply OOP concepts in practice. They may understand variable assignment, if-then-else, loops, functions, even modules, but what the heck are classes, objects, and methods for??? Why do we need inheritance and polymorphism? How do you use these things when writing programs?
Let’s look at how program code can be written at the simplest, lowest level and then progress upward toward something that is easier to manage in terms of size and complexity. Suppose we wrote code in the dumbest way possible: as a huge ream of instructions in a single file. It might look something like this:
main program:
======================
======================
======================
if ===================
===================
===================
===================
======================
======================
======================
while ================
===================
===================
===================
===================
======================
======================
======================
======================
======================
for ==================
===================
===================
===================
======================
======================
======================
======================
if ===================
===================
===================
===================
else =================
===================
===================
===================
======================
======================
======================
...
This could go on for thousands and thousands of lines! It could contain many instances of wasteful code duplication. It would be difficult to read and comprehend, as you lack guide posts to remind you of where things are happening.
So this is where our first programming paradigm arises from. It’s called procedural programming, and it employs procedures or functions to break down our endless ream of code into more manageable pieces. A procedure or function is a block of instructions that can be called from anywhere; it can also be called repeatedly thus saving code duplication. (A function is a procedure that returns a value.) Here is how it might look like:
main program:
======================
======================
======================
call fred
======================
======================
if ===================
===================
===================
call eric
======================
======================
======================
x := bob()
======================
======================
while ================
===================
===================
======================
======================
call eric
======================
======================
======================procedure fred:
======================
======================
======================procedure eric:
if ===================
===================
===================
======================
======================
======================function bob:
======================
======================
return ===============
This is a vast improvement on the original code base. However, as the program continues to grow in size, even this could get out of hand. We can ameliorate the situation by introducing the idea of modules. A module is simply a collection of functions and a data structure that these functions operate on. Generally, a module represents a cohesive abstraction of some sort — the data structure stands alone as something meaningful and the collection of functions sort of belongs together with it. Now, our code looks like this:
main program:
======================
======================
======================
call fred
======================
======================
if ===================
===================
===================
call eric
======================
======================
======================
x := bob()
======================
======================
while ================
===================
===================
======================
======================
call eric
======================
======================
======================module Tom:data:
======================
======================procedure fred:
======================
======================
======================procedure eric:
if ===================
===================
===================
======================
======================
======================end module Tomfunction bob:
======================
======================
return ===============
Mentally, you can better organize your thoughts about this program. Module Tom is a big block of code that you can think of as a single unit. You don’t need to delve into its details unless you have to. It’s a very useful way to “abstract” your code.
Now, you might think that this is the be-all and end-all of managing program complexity. What more do you need when you have modules?
There is, however, a way to abstract your code at a higher level to make it easier to understand and more easily extensible: model your programming solution as a collection or network of collaborating objects. This is what brilliant visionary Alan Kay had in mind when he created the Smalltalk programming system back in the 1970s at Xerox PARC.
While the seeds of object-oriented programming may have been planted in Simula 67, it was Smalltalk and Alan Kay’s conception that catapulted OOP into the limelight. Thereafter, Smalltalk directly inspired nearly every other OOP language we use today.
So what is the idea behind OOP? An object is really the evolution of the module concept. An object is an entity that encapsulates data and behaviour, where behaviour is the set of functions or “methods” that operate on the data. Sounds an awful lot like a module, doesn’t it?
But there are a number of critical differences. First, the data that an object encapsulates is hidden from the external world. This is not the case with a module.
Second, an object is typically a much finer-grained and concrete abstraction than a module. It often represents something in the real world. It can be extremely small and simple. It is much more cohesive than a module.
Third, according to Alan Kay’s conception, an object is very much like a computer with its own private internal state and a communications protocol. You communicate with an object by sending it messages. You ask an object to do something for you by sending it a message and it responds, just as a real computer server in a network might do. And just like in a real computer server, you are not privy to its internal state.
An object is not an Abstract Data Type
…where Abstract Data Type is a highfalutin term for a type of data structure.
OOP languages like Java and C++ are a bastardization of Alan Kay’s OOP conception. They make OOP harder than it has to be, and are an endless source of confusion for many. As Robert C. Martin says in “OOP vs FP,” objects are bags of functions, not bags of data. Objects are not data structures.
And neither are modules.
Fourth, unlike a module, an object can inherit data and behaviour from another object, a “parent” object, and add extra data and behaviour. This can be very useful for extending the functionality of a program. It can save on code duplication.
Inheritance goes hand-in-hand with another concept: polymorphism. When you send a message to an object, the object may respond by calling one of its methods, or it may call a method in its parent object. The object decides, not you.
A class is a template for object creation. It contains the complete definition of any object that is created from it. When we create an object from a class, we say we instantiate the class. This is rather analogous to declaring a variable of some type from a module. Once an object is instantiated or a module data structure is declared, you can then proceed to call methods or functions that operate on the data.
Using RKE pseudo-code, our example looks like this:
main program:
======================
======================
aDick := new Dick # instantiate using class Dick
aDick.fred() # send message fred to aDick
======================
======================
if ===================
===================
===================
aDick.eric()
======================
======================
======================
x := bob()
======================
======================
while ================
===================
===================
======================
======================
aDick.eric()
======================
======================
======================define class Dick:data:
======================
======================method fred:
======================
======================
======================method eric:
if ===================
===================
===================
======================
======================
======================end class Dickfunction bob:
======================
======================
return ===============
When you get right down to it, there really isn’t that much difference between calling a procedure, calling a procedure from a module, or calling a method from an object. It is simply a matter of how you choose to abstract data and behaviour (functions).
In OOP, you must identify opportunities to encapsulate data and functions in a reasonable manner. You may draw inspiration from the real world. You may apply creativity and imagination. Whatever works for you.
You will find that OOP is merely an extension of procedural programming and modules. It is not as hard as you think it is, especially if you use Smalltalk and not one of the major languages like Java, Python, C++, and C#.
For some examples of OOP, read What is Object-Oriented Programming?