by Paul Curzon, Queen Mary University of London
All change
We’ve seen in the previous blog post that privacy is an important idea in programming and especially object-oriented programming. Despite the word, privacy in object-oriented programming is not really about keeping secrets, though. It is about simplifying programming, and in particular making it easier to change things without introducing bugs. Clients rarely know what they want at the start and they frequently change their minds even when they did know. Also early decisions by programmers may turn out to be poor as they were still understanding the problem, and code may need to be changed to improve it: make it faster, use less memory, and so on. It can also be useful to write simple code to start, which you know won’t be good enough for the final version, but gets something up and running quickly. Later, once you know your ideas work, you improve it to make it go faster. One really important idea that helps make this easy to do is abstraction – hiding information to make a problem easier to think about. The programmers idea of privacy is all about abstraction. It is about segregating different parts of the program so changes to one part don’t unduly affect another.
Is it easy to Change a Contestant?
Let’s return to our program creating Strictly Contestants from the last blog to illustrate the idea. Our contestants were described in terms of the pair’s names and their single Total Score. It is calculated by adding together the 4 judges marks.
DESCRIPTION OF A Contestant: PRIVATE CelebrityName: String PRIVATE ProfessionalName: String PRIVATE TotalScore: integer
When creating it we thought that the total was the only score needed, but now our client, the producers of Strictly, are talking about wanting to include the separate judges scores in a version of the leader board for the web. To prepare for that new code, we are going to need to change our Contestant object to store the judge’s scores. By now we’ve written thousands of lines of code that uses our contestant code, accessing the score for different purposes. If we make a change, do we have to check all that code in case our change breaks things? Could we need to make changes throughout the program? If we do have to then there is a strong chance we will make mistakes. It would be easy to miss something we need to change, or make the wrong change in some places. It could also be a lot of work.
We might have had to do it, had we not coded in a sensible way! As it is, a few small changes in a specific place should be enough.
Quick Change
We made the details of the contestants PRIVATE. That means we can change those private details without it affecting any other code as long as the few methods we provided to access the data about contestants still do the same thing. We should be able to make the change with only a few lines of code changing. We won’t even have to look at the rest of the program. Let’s see.
We now need the program to remember the four individual marks rather than the total. We need to replace the TotalScore instance variable with four new ones:
DESCRIPTION OF A Contestant: PRIVATE CelebrityName: String PRIVATE ProfessionalName: String PRIVATE Judge1Score: integer PRIVATE Judge2Score: integer PRIVATE Judge3Score: integer PRIVATE Judge4Score: integer
This description replaces the old description. So far so good.
That part is straightforward. However, the rest of the program still needs the total score. We wrote a PUBLIC method to provide that information whenever needed. We must make sure it still works, given this new representation of a Contestant. It was written:
TO GetContestantScore RETURN TotalScore
We just returned the total score we had stored. We can’t do that any more, as we haven’t stored it. However, we can make the method calculate it whenever it is needed and return the same answer as before. Our new version is:
TO GetContestantScore RETURN (Judge1Score + Judge2Score + Judge3Score + Judge4Score)
The key thing here is that to the outside world – any part of the program using this method, it does exactly the same as before. The fact that it does it in a different way is invisible to code calling the method. Any call to the method expects to be given an integer that is the total. That is what used to happen and it is still what happens.
To make this work, we need to set the right values in those judge scores so that needs a change to. Before the method that did it was:
TO SetContestantScore GIVEN judge1Mark AND judge2Mark AND judge3Mark AND judge4Mark: TotalScore = judge1Mark + judge2Mark + judge3Mark + judge4Mark
Now we need it to set each judge’s value separately as there is no TotalScore instance variable to set.
TO SetContestantScore GIVEN judge1Mark AND judge2Mark AND judge3Mark AND judge4Mark: judge1Score = judge1Mark judge2Score = judge2Mark judge3Score = judge3Mark judge4Score = judge4Mark
Each of the four marks this method is given (referred to as judge1Mark and so on), is stored in the appropriate instance variable (judge1Score and so on) so stored in the object. Again, after the change, all calls to this method throughout the rest of the program still work exactly as before.
There is one more thing we need to change, the constructor, (the method that creates new Contestants). It was
TO CREATE A NEW Contestant GIVEN celeb AND pro: CREATE A NEW OBJECT WITH SPACE FOR THE ATTRIBUTES NAMED ABOVE THEN DO THE FOLLOWING CelebrityName = celeb ProfessionalName = pro TotalScore = 0
We need it just to set the new instance variables, the judges marks, instead of TotalScore:
TO CREATE A NEW Contestant GIVEN celeb AND pro: CREATE A NEW OBJECT WITH SPACE FOR THE ATTRIBUTES NAMED ABOVE THEN DO THE FOLLOWING CelebrityName = celeb ProfessionalName = pro judge1Score = 0 judge2Score = 0 judge3Score = 0 judge4Score = 0
Nothing to change
The rest of our program that used this class with commands like the following doesn’t change at all. For example code that sets up and uses Contestant objects like the following is unchanged:
Pair1 IS A NEW Contestant USING “Alexandra” , “Gorka” Pair1.SetContestantScore WITH 9, 10, 10, 10 DISPLAY Pair1.GetContestantScore ()
It just works. The compiler knew that the instance variables were private as we told it, so it enforced the fact that they were not used.
No difference can be seen
The methods, the parts that are public so that could be used elsewhere in the program, are completely unchanged in the way that they are used and the way they behave. If the program is being written by a team, with you working on the Contestant part, then none of the rest of the team even need to know you made a change to the underlying implementation. This style of programming, using methods to access data structures can be used in a procedural program too, and it is a good idea to do so. However, without the object-oriented infrastructure like the class structure and a way to make things private, the compiler can’t help make sure you stick to your rules. Someone could accidentally use one of the variables elsewhere and the compiler wouldn’t know to stop you.
Change a little, change everything
Just by changing a few lines in a very localised part of the program, you have changed the implementation so it can now deal with a request to display the judge’s scores. Of course to do that needs some new code written to actually add the new functionality. When requested you just add appropriate methods that release the judge’s scores making them public so visible to the rest of the program. Those methods can then be used elsewhere as needed.
Had we not used abstraction and made the instance variables themselves public instead of private, then we WOULD need to find every place they were used throughout the whole program and change them. By using methods, we restricted the place that changes were needed to a small and clear part of the program – the class where we define what a Contestant is. We do not even need to look elsewhere for possible changes. We know there can’t be any.
This is abstraction in action. Precisely because the implementation details of a Contestant are hidden means making changes is easy. Hiding the internal representation of an object and instead making an interface available to them in this way is what we mean in object-oriented programming by encapsulation.
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
- A decomposed face: What is an object? (4 October 2017)