progbox.co.uk
 
.site

Object Oriented Programming - An Introduction

Object Oriented Programming. Just what is this all about, and why should we be using it. Procedural programming has done us great so far, so why should we be bothering with classes, members and inheritance. This article is written to try to help understand what OOP actually is, and through the use of an analogy, help you to understand how useful it can be. Personally, I love a good analogy, and I’ve used this one to teach kids of 14 and 15 to understand the OOP model.

So what is a model?
A model is a specific way of think about a problem and a specific way of approaching it. We all know that there are many ways to attack a problem. If you were going to write a letter to a friend you could follow the standard way of letter writing, by obtaining a pen and paper, or you could go down a different route and email it. Models are a little different to this, they are more concerned with the underlying mechanisms behind solving a problem. In most cases the result is going to be the same, or indeed very very similar, however choosing the right model, may save you hours of time. If you had to store 25 names in an address book on the computer, you could create 25 variables and write search routines to search all 25 variables for the right result. If you were smart about it you would put the names into an array. If you were really smart and were considering scalability, you’d probably put them in a database. Variables, arrays and databases are in this case, different models which can be applied to our problem, to obtain a solution.

OOP takes this idea of a model one step further. It isn’t so much concerned with the specifics of a problem, but more over of all the problems that could be thrown at it. If defines a way of programming and also a way of thinking. So exactly what is it and why should we consider it.

OOP in a nutshell
OOP is a way of classifying parts of a program into objects. These objects are usually containers that group functions and variables and classes, collectively known as members, into logical sets. On its own, that statement seems very hand wavy and not at all specific. So how are we going to demonstrate what we mean, after all you could argue that good comments and structure in a piece of code are all that is needed to groups together functions and variables. We’re going to start with our analogy, and we’re going to start with a variable.

A blank slate
A variable, in our analogy, is a piece of paper. It can contain anything, just like a variable in real programming. It has space at the top for a name, an identifier, but overall it is just a simple container for data. In our analogy the paper can have text or pictures on it. We won’t worry about what format the data is in, as long as it is readable by humans. They play a big part in out analogy too. The variable is a convenient way of storing data, and retrieving it. To store, we write stuff down, to retrieve we read it back. Easy right?

Ok, so next we turn our attention to functions. Functions I like to think of as people at desks in an office. Each person in an office generally has a task, and this is same kind of idea for functions. They are created to perform a task. You give them an input, and generally expect some kind of output. Generally you ask the person to perform a task with some initial data. This is where our analogy comes into play again. Functions are given variables, people are given pieces of paper. So generally a function definition will define what variables a function expects, and what they are going to be called in the local scope of the function.

So in the analogy, if we were to call a function, it would be the same as showing the person some pieces of paper with some data. The person at the desk would then copy this data down onto their own pieces of paper, and write their own variable names at the top. Make sense? The function person then performs their processes, using their variables and ends up with some kind of answer, or result. Generally most functions either return some data or ask another function to perform a task. So they either write down their answer on a piece of paper and pass it back to their supervisor, or they take some of their papers to someone else’s desk and ask them to perform the function.

Now for the moment, we’re going to think about single threaded procedural programming. Only one person can be working at any one time. So supervisor passes data to the first function, who then starts working, whilst the supervisor just stands there., doing absolutely nothing until the function finishes.

So what happens when we start thinking about a class, and indeed objects? What is a class? A class is a kind of logical way of grouping together a set of functions and variables, and even classes, commonly known as members. So how does this fit into our analogy? We can think of a class as being a blueprint of an office. Bear with me, we need to explain a few things first. When you create a class in your program, or more accurately when you are typing in the code that makes up a class, you are really only typing in a blueprint for that class. If you type in the definition of a class and run your code, it will do absolutely and completely nothing, the same as if you code a function and never call it.

Classes have to be instantiated. The have to be told to exist. When this happens, the computer sets up a whole new place for the class to sit in memory. If the class has a constructor, this is run immediately after the creation of the class and may do things like set initial variables and so on. The class has its own variable space, similar to a function, but usually this can also be shared between functions too.

So how does this fit into our analogy. Well, when we write the code, we define the blueprint for the class. When we run the code and we ask for a class to be instantiated, we actually technically build the office. We put the people inside who are going to do the work. We issue them pieces of paper with names on the top.

When a function ends, its variable space is destroyed. It’s like taking our office worker out into the back yard and *cough* *cough*, doing away with them. We burn their desk, and their papers and it’s as if they never existed. Classes are different. A class doesn’t have to be in use to exist and more importantly, you can have more than one instance of the same class. This is where things get very interesting and very useful. But how do we use classes? Why do we need them?

Well let’s take a general view of a business. A business will generally have a manager, and possibly a human resources department. It’ll have office workers, a receptionist, and a cleaner. This is almost like the blueprint we were talking about. It’s the base view of what a business does. So if we wanted to create an instance of a business, we’d lease a building and hire people to perform those functions. We’d probably even buy them paper.

Now, say we wanted another business doing a very similar job, but called a different name. Well why waste time writing a second lot of blueprints and job descriptions? The same blueprint will probably work fine for this second office. The only difference in this new business is a) the name, oh and we want to have a tea lady too. All we need to do is add the function for a tea lady to our class. This is called inheritance. We create a new blueprint, based heavily on the first, but we add to it.

Say now, we want a third office, but we want to change the job description of the manager. That’s fine, we can do this. It’s called overriding the function. We create an instance of the class, but we rewrite the function for the manager to be slightly different. Easy right? Not all programming languages support inheritance, and not all support overriding

So our program becomes an office block, with offices inside being created and destroyed at the coder’s whim. Let’s take a look at a real life example of using classes.

A while back I worked on a project called VCSFrenzy. It was my first real OOP piece of code. The system was designed to watch version control systems for changes and then notify the user when a change occurred. It was built to work with SVN, BZR and a few other VCSs. So how was it implemented using classes? There was a configuration file where you would define a version control database and it’s parameters, this was read in at the start of the program and instances of certain classes were set up depending on the type of version control system being used.

Internally I had a base class which we’ll call notify. This had functions like parse the incoming data from the VCS, read the data from the VCS, construct the output for the notifier, notify the user, tell me your name, tell me your latest revision number. I then created new classes which inherited notify, but changed and overrode some functions which would be specific to the VCS system, such as, read the data from the VCS and parse the data from the VCS. These new classes, called notify_svn and notify_bzr for example, were both very similar to notify but had subtle differences.

When the configuration file was read, the program determined which type of class to use, and then instantiated it, populating it’s variables with things like VCS server, username, password, notification length, icon etc.

Now if I wanted to change the way a notification was output, I just changed the notify base class, and because the others inherited from it, they all changed too! Magic eh?

Whilst the program was running I had another GUI part that would give a summary of each VCS, its current version, the name and an icon. To do this, the program would simply go to each instance of the class and say, “tell me your name”. This was a function in the base class remember that would output the VCS class instances name, as defined in the configuration file.

Hopefully from this, you can see just how useful classes are. Remember that in the first instance we are only dealing with single threaded systems. Only one person can be moving at any one time. Imagine our office block as a child’s toy, almost like a doll house. The child can only move one doll/person at a time. This is a single core computer. We can fool the user into thinking we are doing many things at once, by moving one person, and then quickly moving the next. In fact this is the essence of multi tasking. The trick is, who is the most important person to move? This is where the notion of nice in linux comes into play. Processes with higher nice values are given a bigger share of attention from the child.

Threaded systems need more thinking about. One person may not be able to complete their task until the other one has finished theirs. They may have to wait. If they try to proceed, things may break. Imagine a lift that has no door on it. One office worker goes to walk into the lift, before it has come back up again from taking the previous person downstairs. Big accident.

Now just think how much more complicated it would be to program a parallel processing program. One that runs on two processors simultaneously. Having two children playing with the same doll house at the same time. As we can imagine., if that’s not done properly, if the doll house isn’t deigned well……..FIGHTS WILL BREAK OUT……and in the computer world……FIGHTS = CRASHES.