What is Object-Oriented Programming?

So, you think you're getting the hang of the programming basics - you understand the key techniques, you might have even experimented with other uses of arrays, and then someone mentions "object-oriented programming". You've done a quick search using Google - it's in the A level specification and it's all sounding a bit complicated. What doesn't help is that explanations tend to use obscure examples - there's a lot of vehicles - and if you don't really understand these objects then you won't know what to do with them. I'm going to attempt to give you a simple overview of object-oriented programming using something with which we're all familiar - rectangles.

What Are Objects?

You might have written a program in which there are multiple occurrences of the same type of "thing" - e.g. a game with several balls. You might position the balls using x- and y-coordinates, and they might have a size, a colour, a speed and a direction. There might also be things that we want to do with those balls - move them, check for collisions, get them to bounce, etc.

With "traditional" programming techniques, you'd do these with variables and functions. That's six pieces of information per ball, all of which need to be stored in variables. You could call them x1, x2, y1, y1, size1, size2, etc., or you could use arrays/lists of these values. You'll then need to create the functions for moving, colliding, bouncing, etc., and tell these functions which ball to modify. It can all get a bit messy.

In programming, objects are just data structures that represent "things" in the program - in this case a ball. The use of objects can tidy up all of these multiple variables and functions into a nice tidy package and make them easier to manage. Each ball, as an object, will have properties, such as the position, size, colour, etc., and methods, which are things that we can do to the ball, such as changing direction. Really, though, properties and methods are still variables and functions, they're just tucked away, out-of-sight, inside the object.

So What's a Class?

When people first read about object-oriented programming, the difference between classes and objects can seem quite confusing. Most books talk about an object being an "instance" of a class, but here's perhaps a simpler way to think about it.

If I look up the word rectangle in the dictionary, I see an explanation of what a rectangle is - but I don't see an actual rectangle. A definition isn't the same as an example.

A class is, effectively, a definition of what an object will look like. We can describe what a rectangle is, and some of its properties (height, width, etc.), but that doesn't give us a specific rectangle; it's just a pattern or template for making a rectangle. I can then use the class to create an actual rectangle by specifying a height and width, and this becomes the object.

An Example - Rectangles

I'm going to use Python for my example because it appears to be the most popular language in schools at the moment, but the principles also apply in many other languages - I first came across them in C++ in the 1980s. You can download the example Python script here (right-click to download rather than opening in the browser), or view it in Repl.it.  There is also a video introducing this concept on the Computing and ICT in a Nutshell YouTube channel.

First we need to create the class from which the rectangles will be created. It tells Python what properties a rectangle will have, and what methods. There is a class keyword that defines the class, but inside the class definition the properties and methods should look familiar - they are just variables and functions. The main difference is in how they are used - they are accessed using a full-stop between the name of the object to which they apply and the name of property or method. For example, if a is a rectangle, you can access its width property using a.width. This is useful because rectangle b will also have a width, and we can use the same name for it, e.g. b.width.

The function definitions inside a class have an extra, "special" argument, called self (which you don't actually use when calling the function, it just helps you to know which object it is that you're referring to). The property self.width is therefore just the width property of the rectangle that you're working with on the moment. The example will hopefully make this clearer.

There are also "special" or "magic" functions that you can use to define how your objects behave, and these have names that begin and end with double underscores. You will need at least one of these, __init__(), as it describes what to do when the object is created (or initialised).

Properties

Here's a example basic class definition for a rectangle:

class rectangle(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height

Note that self is the first argument of __init__, but that I've also included width and height. I've included these because that's the minimum information required to define a rectangle. The two lines in the function set the width and height properties of the rectangle to be the values of width and height passed to the function.

I can now use a command such as a = rectangle(3,2) in my program - or in the IDLE shell - to create a rectangle based on this class. It will have a width of 3 and a height of 2. I can view the width of a by printing a.width, or I could change the height to 4 with a.height = 4.

Methods

Here's where the rectangle example comes into its own. I'm not really sure what to do with a truck class, but I can think of some things that I might want to do with a rectangle. These things are the methods that I can add inside the class, and might include calculations such as finding the area or perimeter of the rectangle. These definitions would go directly below the __init__ function and would be indented to the same level. Aside from the use of self, these behave exactly like standard Python functions and may or may not return a value.

def area(self):
    return self.height * self.width

def perimeter(self):
    return (self.height + self.width) * 2

The method a.area() now returns 6 (i.e. a.height x a.width), and a.perimeter() returns 10 (twice the sum of a.height and a.width). Note that the parentheses are required for methods.

In the downloadable example there are further methods, including some that return no value (e.g. rotate() and enlarge()), and some that return a Boolean value (such as square(), which tells you whether the rectangle is a square).

Operator Overloading

Programming languages know how to compare and perform calculations with variables of standard types. With integers, for example, if a = 2 and b = 3 then a + b is 5, a == b is false and b > a is true. But what if a and b are rectangles? Does it make sense to add two rectangles? How can we tell if two rectangles are the same, or whether one is "greater" than another?

This is what operator overloading does. Operator overloading is a somewhat obscure term that just means redefining standard functions and comparisons so that they can cope with the objects that we've created.

In Python they use some more of the "magic" functions that I mentioned earlier. In the rectangle example I have included:

# equal to
def __eq__(self, other):
    return (self.width == other.width and self.height == other.height) or (self.width == other.height and self.height == other.width)
    
# less than
def __lt__(self, other):
    return self.area() < other.area()
    
# great than
def __gt__(self, other):
    return self.area() > other.area()

So now I can have a = rectangle(3,2), b = rectangle(4,5), and c = rectangle(2,3) and compare them - a == b will be false, but a == c will be true, b > a will be true, and b < c will be false.

It's up to you to decide how these comparisons are made - or if they can be made at all. I have decided that two rectangles are equal if their heights and widths are the same (or one is a rotation of the other), but when using > and < I am using the area, so that a > b will be true if a has a greater area than b.

When comparisons are made, we are comparing two objects - in the arguments for these functions, self refers to the first object and other to the second, so when we check whether a > b, the function returns whether a.area() > b.area().

Finally, if a = rectangle(3,2), then using a on its own (e.g. print(a)), or doing things like int(a) or str(a) will result in an error. You can define in your class what should happen under these circumstances:

# define the "printable" version of the object
def __repr__(self):
    return str(self.area())

# what happens when you use int() on the object
def __int__(self):
    return self.area()

# what happens when you use str() on the object
def __str__(self):
    if self.square():
        return "square"
    else:
        return "rectangle"

Printing a will now give me 6, as will int(a), but str(a) will return rectangle - because that's what I've decided it will do.

Hopefully this has give you a sense of what objects are and how they can be used in your programming. A level students will be expected to have an understanding of these ideas.

There's plenty of help available on-line, particularly if you want to overload an operator that I haven't included here. You might also want to research inheritance - this is where one class is based on, or is a variation of, another. For example, I might want to have a more generic shape class, including extra information, such as the number of sides, and base my rectangle class on that, setting the sides property to four in __init__. I could then also have a triangle class, setting sides to three, etc. 

Update 2020

Repl.it didn't exist when I wrote this article, but there is now a on-line version of this code that you can try for yourself (turn off Google Translate and click Exécuter to run the program).

This blog originally appeared in the TES Subject Genius series in September 2016.