C21CH

Speculative Web Space

Object Oriented Programming

Intro To Code Home

The programming we learned in the Intro To Code course using basic data structures and functions is sometimes called 'procedural programming'. This style of programming is often used it we want to write a small script that does a few basic tasks. Code becomes confused and hard to manage when we want to build something larger, such as an application with a user interface to many different tasks. The most common style in professional programming is Object Oriented Programming (OOP). It builds on those things we have covered already but takes it further.

Object oriented programming is used for many reasons. It makes large amounts of code easier to organise and manage with minimal duplication of code. The way objects work is roughly analogous to the real world, so it makes sense. When done properly it makes it easier to re-use code written for one purpose for some other purpose. For example, our application might need to read text files, or a database - there are commonly used objects for doing these tasks. If we write our own objects we can also share them with others.

Objects

When information structure gets more complicated than scalars, arrays, associative arrays, functions and events it is useful to define 'objects' (or more specifically 'classes', but we'll get to that later). Objects are complex collections of variables, arrays, associative arrays, functions and other objects. Most modern programming languages are based on 'Object Oriented Programming' (OOP). Javascript is very object focused but it is unusual in that it doesn't need to use 'classes'. We can none the less work with Javascript in such a way as to use what would normally be called 'classes'.

'Objects' are like real world 'objects' - they have some attributes and things they can do. A dog has 4 legs and can run. A 'cat' 'object' might have a scalar variable called 'legs' that we set to 4, and a 'colour' variable we set to 'black'. It may have a function called 'Run', and others for 'Climb', 'Eat', 'Sleep', 'Purr'.

'Objects' can be very abstract and often don't resemble real world objects but represent conceptual structures. Look back at our code in the Intro To Code Home course, where we set "document.getElementById("greeting").innerHTML". Javascript treats the whole HTML document as an 'object', that has within it many other objects. The 'document' object has a function 'getElementById()' which returns an html element as an object. This html element object has an 'innerHTML' variable that can be set. These objects are built in to Javascript to make it easy to use. Instead of writing complicated code to go through every letter in the file and figure out where the html begins and ends, and which one is the tag we want, we can just call the document object's 'getElementById()' method. Most languages have many objects built in to make it easy to do things that people commonly want to do. There are libraries of File input/output classes, maths classes, networking classes, error logging classes, and so on. We typically also create our own classes and objects.

Classes

In most languages before we can create an object we need to define what kind of object it is in a 'class'. A class is like a definition that says what properties and methods (or variables and functions) all objects of a particular kind can have. For example, we can define a 'cat' as a kind of animal with 4 legs, whiskers, and one tail, and that it can run, sleep and catch fish. The class is like the general concept 'cat'. Then any particular cat, like 'Felix' or 'Snoops', is an instance of that class, or an 'object'. For philosophers you can think of a 'class' chair as something like a Platonic form, and the chair you are sitting on as an 'object'. Critical theorists will note that OOP is much like Structuralism.

A 'cat' class, in Javascript might look like this:

function Cat () {
	this.name;
    this.color = "black";
	this.hungry = true;
    this.run = function() {
        return this.color + ' ' + this.type + ' apple';
    };
	this.sleep = function() {
		if (this.hungry) {
			alert("Warning: " + this.name + " too hungry to sleep.");
		} else {
			this.purr();
		}
	}
	this.purr = function() {
		alert(this.name + ": prrrrrrrrprrrrrrrr");
	}
	this.eat = function(food) {
		this.hungry = false;
		this.sleep();
	}
}

Now if we want to instantiate an object of this class, ie: create a particular cat in our code (perhaps we are writing a game involving cats) we would simply write this:

var MyCat = new  Cat();

Note that the cat object is stored in a variable called MyCat (you could create arrays of cats, etc). The cat we just created would immediately have all the properties and functions defined in the cat class. In this way you can create as many cats as you like without having to write out all the cat code over and over again. You can then call the methods defined and access it's properties, eg:


var MyCat = new  Cat();
MyCat.sleep();

What will happen when we tell the cat to sleep (call the 'cat' object's 'sleep' method)? According to the function defined in the class, this will let us know that the cat can't sleep because it's still hungry. Note that we set cats to be black by default (which we could change), but some other properties are 'null' or have no value, until we set them, eg:


var MyCat = new  Cat();
MyCat.name = "Snoops";
MyCat.color = "Purple";

The cat provides an example that is relatively easy to understand. We could have various kinds of food classes, such as fish classes, or chicken classes, etc, to feed it. Note that the .eat(food) method can have a variable passed to it, the variable is called 'food'. Object methods work just like functions, but when you call them, they only apply to this particular cat. If I instantiate a cat and feed it, I don't feed all the cats, just this one.


var MyCat = new Cat();
MyCat.name = "Pocket";
var MyOtherCat = new Cat();
MyOtherCat.name = "Snoops";
var Pilchards = new Fish();
MyCat.eat(Pilchards);

MyOtherCat.sleep();

This code should give us an alert saying "Pocket: prrrrrrrrprrrrrrrr" and another alert saying "Warning: Snoops too hungry to sleep." (Right click and view source to see the code. Note we had to create an empty 'Fish' class to get it to work. What methods and properties might a 'Fish' have, if we were making a game about cats and fish?)

Before continuing, let's just have a look at how this concept is common across many major languages, and that it is often only a matter of using a different syntax to use a different language.

PHP:

class Cat
{
    public $name;
    public $colour = "black";
	public $hungry = 1;

    public function sleep {
		if ($this->hungry) [
			echo 'Warning:' .  this.name . ' too hungry to sleep.';
		} else {
			$this->purr();
		}
	}
	public function purr {
		echo this->name . ": prrrrrrrrprrrrrrrr";
	}
	public function eat($food) {
		$hungry = false;
		$this->sleep();
	}

}

Java (not to be confused with Javascript):

public class Cat {
        
    private String name;
    private String colour = "black";
    private Boolean hungry = true;
        
    public function sleep {
		if (this.hungry) [
			Console.Writeln('Warning:' .  this.name . ' too hungry to sleep.');
		} else {
			this.purr();
		}
	}
	public function purr {
		Console.Writeln(this.name . ": prrrrrrrrprrrrrrrr");
	}
	public function eat(food) {
		this.hungry = false;
		this.sleep();
	}
}

It's easy to see how classes and objects are similar to things in the real world. Object properties are like nouns or adjectives. Object methods are like verbs. Classes are like types or categories of things. But in code classes and objects can form part of a representation of anything - cats, banks, credit cards, mathematical formulas, network connections, places on a map, books, authors, images, movies, words in a text and so on.

Built-in Objects and Libraries

Programming languages usually have 'libraries' or 'packages' of classes and objects for performing common tasks, making it easier to simply create an object and call a function etc, instead of writing many lines of code.

For example, just about every programmer, at some point, wants to open a file and read information from it, or write data to it, such as when you want to get data from a csv file. Instead of writing a lot of difficult and complex code to access memory and navigate Operating Systems' file structure conventions and so on, just use the 'File IO' package built into the language. In Javascript, for example (though we don't often need this in Javascript because it is a client-side web language) we can use FileReader.readAsText() to open a file and read it's text.

Usually when we open a file it is for either reading or writing. In this Python example from https://www.tutorialspoint.com/python/python_files_io.htm, we create a 'file' object, passing 'w' to the constructor to say that it is writable, then write to it, then close it so that it doesn't remain locked.

#!/usr/bin/python

# Open a file
fo = open("foo.txt", "wb")
fo.write( "Python is a great language.\nYeah its great!!\n");

# Close opend file
fo.close()

Java has a large IO library for handling many specific kinds of input and output, such as text files or streams of binary data, and accessing it in different ways, such as to read it all in at once or to loop through it line by line in a way that conserves memory.

Most languages will have libraries for these common tasks, though they may go by different names:

Classes and Objects For The Learn Italian App

If we want to improve the Learn Italian application, we could create word 'objects' with properties and methods (a method is a 'function' that belongs to an object). Such as:

function word(wordText, language, partOfSpeech, englishTranslation) {
    this.wordText;
    this.language = language;
    this.partOfSpeech = partOfSpeech;
    this.englishTranslation = englishTranslation;
    this.exampleUses = [];
    this.addExampleUse = function (usage) {
        this.exampleUses.push(usage);
    };
}

Here we declare an 'object' as if it were a 'function' with values passed in. These values must be passed in each time we create a new instance of the object.

Note that this 'object' includes a 'method' or 'function' to add sentences to an array of example sentences. Once defined, an instance of this 'object' can be created and used like this:

var AWord = word("gato", "Italian", "noun", "cat");
AWord.addExampleUse = "Il gatto mangia pesce.";
AWord.addExampleUse = "Il cane inseguito un gatto.";

We could construct arrays of words like this and use their variable properties to, for example, allow the user to click to show only verbs or nouns, or to display example usages.

Check you understand:

See if you can understand what is happening in the code below (or get it from ilgato.html and right click to view source). It is a little complicated and challenging for a beginner but one of the best ways to learn is to try to think through problems such as these. Programming involves a lot of problem solving and creativity. At times this makes it frustrating, but it is equally as rewarding when it works. When trying to solve problems, remember, 'Google is your friend'. (After 18 years I still search for solutions and code snippets or to check syntax every day I code.) You can see how it uses only what we have learned so far as building blocks to make a more powerful and interactive application that could be extended to handle many Italian words.

Tip: When trying to understand some code, or to debug your own software, work from beginning to end or from the end to the beginning. You click the button - what happens next? Or you expect a certain piece of output and work backwards from where you expect to see it, to see why it's not as expected.

    <html>
    <head>
        <title>Learn Code</title>
    </head>
    <body>
        <h1>Learn Italian</h1>
        <p>Choose animal:</p>
        <button onclick="setWord('cane')">cane</button>
        <button onclick="setWord('gato')">gato</button>
        <p>Show:</p>
        <button onclick="showEnglish()">English Translation</button>
        <button onclick="showUsage()">Example Usage</button>
        <button onclick="whoChasesWho()">Who chases who?</button>
        
        <p id="englishword">English: </p>
        <p>Example use: </p>
        <ul id="egusage">
        </ul>
        <p id="whochaseswho"></p>
        
        <script>
                
                // define the 'word' class.
                function word(wordText, language, partOfSpeech, englishTranslation) {
                    this.wordText;
                    this.language = language;
                    this.partOfSpeech = partOfSpeech;
                    this.englishTranslation = englishTranslation;
                    this.exampleUses = [];
                    this.addExampleUse = function (usage) {
                        this.exampleUses.push(usage);
                    }
                }
				
                // a variable to store the word the user selected
                var wordToUse = "";
                
                // create some word objects
                var AWord = new word("gato", "Italian", "noun", "cat");
                AWord.addExampleUse("Il gatto mangia pesce.");
                AWord.addExampleUse("Il cane insegue il gatto.");
                
                var BWord = new word("cane", "Italian", "noun", "dog");
                BWord.addExampleUse("Il cane insegue il gatto.");
                BWord.addExampleUse("Il cane e affamato.");
                BWord.addExampleUse("Il cane scodinzola la coda.");

                // to be called by the onlclick event when user chooses a word
                function setWord(chosenWord) {
                    wordToUse = chosenWord;
                }
                
                // show the English translation of a word.
                function showEnglish() {
                    var englishWord = "";
                    if (wordToUse === "gato") {
                        englishWord = AWord.englishTranslation;
                    } else if (wordToUse === "cane") {
                        englishWord = BWord.englishTranslation;
                    }
                    document.getElementById("englishword").innerHTML = "English: " + englishWord;
                }
                
                // list example usages
                function showUsage() {
                // set the chosenObject to AWord by default
                    var chosenObject = AWord;
                    var outputHtml = "";
                    
                    if (wordToUse === "gato") {
                        chosenObject = AWord;
                    } else if (wordToUse === "cane") {
                        chosenObject = BWord;
                    }
                    for	(i = 0; i < chosenObject.exampleUses.length; i++) {
                        outputHtml = outputHtml + "<li>" + chosenObject.exampleUses[i] + "</li>";
                    };
                    document.getElementById("egusage").innerHTML = outputHtml;
                }
                
                // generate a sentence from user selected options
                function whoChasesWho() {
                    var subject = wordToUse;
                    var object = "";
                    if (wordToUse === "gato") {
                        object = "cane";
                    } else {
                        object = "gato";
                    }
                    document.getElementById("whochaseswho").innerHTML = "Il " + subject + " insegiuto il " + object;
                }
                

        </script>
    
    </body>
</html>

Debugging

Code almost always has bugs in it the first time we run it. One of the biggest problems in estimating how long it will take to do a software project is the difficulty in estimating how long it takes to fix bugs. One full-stop in the wrong place can break your code and it can take you 5 seconds or days to realise that this is the problem, where it is and fix it. If you write some code and it works the first time without any errors, you should be worried. There is probably a problem you can't see yet.

If we are lucky our Text Editor, IDE or the runtime error message will point us straight to the bug. Often error messages even give us a line number, a code snippet and a brief message explaining the problem. If that doesn't solve the problem right away Google it. Usually someone has already had the problem and posted it on a discussion board and several people have offered alternative answers. This at least points us in the right direction.

Debugging is part of the learning process. Software development is not something you learn and then practice. Partly this is because technology changes fast, but also because no one person can know everything and each new problem is likely to require understanding something you don't already know. Day to day work always involves looking up and learning something new. When we are debugging, especially when beginning, we often go down the wrong path, looking for solutions in the wrong places. However, in doing so we get a lesson about something we otherwise would not have. Later, when there is another problem we find we can solve it quickly because we learned about it when trying to solve some other problem. Instincts improve with time and tenacity is rewarded. It always feels good to finally have made something that works. With more experience your hunches about where the bugs are get better. What would once have taken hours to spot, soon takes minutes.

If someone else is telling us about the problem, or we can't remember what settings we set and what order we clicked things in, try to reproduce the problem. You can't know it's fixed if you can't see how it's broken.

Always debug in a methodical way, changing only one thing at a time, and running to see if anything has changed. If you change many things, it might work but you still won't know what the problem is, and will still have to go back and work through each of those changes one at a time. It's tedious but a boring half day is better than 2 days banging your head against the wall.

As an example, all our Uni website's course listings once went down because of a single character that was invisible because it was badly encoded after cut and pasting from word into XML. Because we understood the system as a whole, we knew a good place to start would be the XML feed. We then verified there was a problem with the XML by putting it in a different system which also failed. The only way we isolated this problem was by proving first that a small amount of correct XML worked then progressively halving the bad XML file and it's contents, down to the specific word. Even though the cause of the problem was still completely invisible, deleting and retyping the word and spaces either side of it corrected the problem.

Is the problem in the process, the form of the data or the values of the data? Generally speaking the best strategy for debugging strategy is to isolate the problem:

  1. Backup everything before you change anything.
  2. Start from the beginning and carefully look at each step as you go forwards to check it all looks right. Or start from the output you expect and work backwards.
  3. To debug code, use 'breakpoints' if your text editor or IDE allows it (Chrome and Firefox's developer tools enable you to put breakpoints in Javascript when it loads in the browser.)
  4. Check the data looks clean (open csv files in a text editor to check Excel isn't masking any problems)
  5. If it makes sense, try the data another system that is known to work, to see if it has a problem with the data. (eg: does a csv or xml file open ok in another system that uses csv or xml - that helps isolate if it is a data or system problem)
  6. Is the form of the data or the values of the data the problem? Check that one item of data which is easy to visually check, works. If not, maybe its the form of the data (wrong data types such as numbers coming in as strings, wrong amount of columns, wrong column names, spaces in column names, should have no column names etc).
  7. If you suspect the values in the data break the data in half and see which half the data problem is in. Then break that data in half etc. Or just keeping adding blocks of data from the beginning to the end.
  8. If you have checked everywhere it could be 3 times either you wake up tomorrow and realise it was there the whole time, or as Sherlock Holmes says, "Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth." The problem may be where you don't expect to find it.
  9. Sometimes it's two problems, or three.
  10. Step back and understand the way the system is put together as a whole, so it's easier to see where the problem probably is.
  11. Sleep on it. Go for a walk. Any time I have found a bug unsolvable for a half day or so, after going for a walk or after sleeping, it became obvious I was looking in the wrong place. If it still doesn't work there's more to life than programming and at least you will have seen the sky and got some rest.

Good luck!