Paul Curzon, Queen Mary University of London
Object-oriented programming is an important part of modern programming. The concepts involved are complex though, and if learning to program in this way it is vital to understand at a high level what it is about at the outset. The first concept to get to grips with is just what an object actually is and why we might want to use objects to structure our programs. We will use an example of building an unplugged face to demonstrate.
Learn about: Object-oriented programming, objects, decomposition, simulation, computational modelling
Object-oriented programming (OOP) arose from a desire to write programs that simulate things in the real world. Simulation has given a different way of doing science that compliments experiments: simulate the phenomena in a virtual way. The real world is made of objects and the natural way to do this is to think about programming the behaviour of those objects, whether people, cars, ants, photons or cannon balls, separately. Once one ant’s behaviour is programmed, we can then have lots of them – as many as we like – each following the same rules. From one ant program we can get a whole colony.
If the theory embodied in your program is right, the simulation should match the real world behaviour. If we understand ant behaviour and have programmed it correctly, then our virtual ants should behave like a real ant colony. If they don’t we must inspect our rules and work out what needs to change, and so improve our understanding of ant behaviour. This computational modelling of phenomena of interest is one of the main ways Computational Thinking has changed the way the Sciences are done.
OOP also gives a powerful general way to write programs, from games to airline booking systems. As we will see it is really all about decomposition. It gives a new way of organising a program: breaking it in to parts that can be written separately.
Let’s demonstrate by simulating human expressions on a robot face. Here is a video of a robot doing the sort of thing we are interested in. It doesn’t understand the words spoken. It just reacts to the tone of the person’s voice, giving an appropriate expression. If the voice is angry it looks unhappy. If the person talks softly then it cheers up. If they speak suddenly, it is surprised.
Procedural Programming: Rules for Expressions
How do you write a program to do that? For each expression you need to write rules that move the mouth, eyes and eyebrows in the right way. You could try and write rules about the whole face. It’s always a good idea, though, to break up a program in to separate parts to make it easy to write. Then you can program and test each on its own. Each is a smaller and more manageable problem.
Here you might decompose the program by different expressions. First you might write a procedure, called Happy, that controlled all the parts of a face to give a happy expression. Once that worked, you might write a procedure called Sad to give a sad face, and then one called Surprise that looked surprised, and so on. Each of these procedures would include instructions about the whole face. In procedural programming the focus is on decomposing the program in to the separate operations, separate procedures, like this.
Objects: Rules for Eyes, Eyebrows and Mouth
Instead of thinking about expressions, another, completely different way to think about decomposing, and so programming, the face is in terms of its individual parts: the objects that make up a face. A face is made of eyes, eyebrows and a mouth (and other things we will ignore for now). We can specify their behaviour separately from the behaviour of the rest of the face. We can work out what eyes do without worrying about eyebrows, mouths or even noses. They can be added later. In effect to simulate a face, we can separately write mini-programs that simulate an eye, an eyebrow and a mouth.
An unplugged face
Rather than write a program we will demonstrate this in an unplugged way as it is the concepts of objects and behaviours that we are interested in understanding here. We don’t want to get bogged down in syntax. First we get volunteers to be our robot. Two people hold eyes, two eyebrows and two the mouth (the bits are made out of Blue Peter technology – card, tube and sticky-backed plastic). Each person represents one of the objects that make up the face.
We have a robot, but it does nothing without instructions. We need to write rules that give the behaviour. Each person needs to be told what to do to control the object they control.
Let’s focus on eyes first. Notice we are now working on a much simpler, though similar, problem – worrying abut simulating eyes rather than whole faces. What is their behaviour? Well, our robot eye can be wide open or narrowed. We want the former when it hears a nice or a surprising noise. We want the latter when it hears a nasty noise. We could at this point decompose, writing rules for each expression separately, but its simple enough we will do it all at once.
The behaviour of an EYE object is:
If NICE SOUND then WIDE OPEN
If NASTY SOUND then NARROWED
If SUDDEN SOUND then WIDE OPEN
This is essentially a program for an eye (just written in a language a person can follow). We can come up with these rules completely separately from the instructions for any other object. If we make two eye objects that follow these rules we already have the basics of a face. We could test it and see if it starts to show the right expressions. Of course we only need one set of instructions for an eye. We can then reuse it whenever we need an eye.
We call the rules for behaviours like this methods, and they are just a form of procedure or function but in an object-oriented context. There is also a distinction between an object and a class.
Our rules for an eye above are really a plan or template for how to build an eye object. It is what we call a class definition for eye objects. We need to create an instance of that class – the actual object – each time we want an actual eye. In our unplugged word of volunteers, creating an instance involves taking a volunteer and giving them each a copy of the eye instructions – they each become eye objects. Our simple face is built of two eye objects – so in our instructions of how to build a face we will need commands to create two such instances of eyes, each separately following the same general rules.
Having done that and tested it to make sure it does the right thing we can move on to programming other objects – writing their class definitions. Let’s do the eyebrows next. An eyebrow can move UP high or be low DOWN over the eyes. For happy and sad expressions the eyebrows will be in a normal, down position, but we raise our eyebrows when surprised.
The behaviour of an EYEBROW object is:
If NICE SOUND then DOWN
If NASTY SOUND then DOWN
If SUDDEN SOUND then UP
Each side of the mouth also then has a similar rule, where the end of the mouth can turn UP (when happy), or it can turn DOWN (when sad), or the mouth can OPEN wide when surprised.
The behaviour of a MOUTH object is:
If NICE SOUND then UP
If NASTY SOUND then DOWN
If SUDDEN SOUND then OPEN
Building the Face
We now build a face object just by putting together the right bits: two eyes, two eyebrows and a mouth. We create instances of them to make a face. Each part follows its programmed behaviours and what emerges is a face acting like a face: looking happy, sad or surprised.
Of course to fully complete the program we need to write instructions as to what UP and DOWN, OPEN, NICE, NASTY and SUDDEN sounds actually are. This is another example of decomposition and linked abstraction given we are ignoring the details of how to code them in this explanation. We ultimately need to write methods to do each of those things.
The Power of Objects
Overall the main way we have decomposed the problem is by thinking of the objects that make up a face and separately programming their behaviours. The face itself might just then be part of a bigger endeavour to make a robot body…what about our body language for different emotions? That might be part of a program to simulate an audience at a concert, which might be part of a city simulation,…It is a natural way to build up large programs from smaller parts.
The idea of objects also has power because they are naturally reusable. Each object can be replicated as many times as needed. Want an alien with three eyes. Just add another eye. Its behaviour is already coded. Want a whole crowd of faces, then just replicate the whole face object. This also naturally scales, at least on the right sort of problem. That is ultimately what it is about, trying to find a style of programming, a form of decomposition, that allows us to write massively large and complicated programs in a way that is possible to do and get right.
Decomposing the problem in to objects in the way we’ve described is only the first step though. Once you have done that, you find other opportunities open open for reusing code in natural ways which leads to more complex concepts like encapsulation and inheritance that give even more benefits.
Catch up with Paul’s other blog posts
- Strictly Private: Abstraction and the importance of ‘privacy’ (18 October 2017)
- Strictly Judging Objects (11 October 2017) With Peter McOwan