Tuesday, November 13, 2012

AP Computer Science: Object Oriented Programming

AP Computer Science: Object Oriented Programming

AP Computer Science: Object Oriented Programming

A Bit of History

I grew up with computers from the late 60's to the present day. Now my next generation (my son) is trying his hand at learning the art. But what should he learn? Do I take him through an entire history of the growing pains of computers where memory was scarce and expensive. Where our programming languages had little in the way of libraries to do useful things? I don't think so. He doesn't need a complete review of the past to come up to speed with the way things are done today. I had to live rewritting my libraries from scratch each time I switched jobs or changed platforms. He doesn't. The field is different today and the popular languages have large libraries associated with them. He and his fellow Comp Sci students should be able to benefit from efforts of previous computer scientists.

When I first started out with computers the BASIC programming language was avaialble on most machines in use at that time. BASIC had FOR loops and IF statements but it also had a GOTO statement. A BASIC program would have line numbers and you would tell the computer to GOTO a certain line number. Programs were littered with GOTOs. Then I got to College and it was proclaimed that GOTOs were taboo. We now had "Structured" programming languages (like PASCAL, ALGOL, PL/1) and a well written program would not even need to use GOTOs. Edgar Dykstra a giant in computer science wrote the classic treatise in a letter to the programming journal "Communications of the ACM" (see reference 1). This was the beginning of the "Structured" programming paradigm, which can be summed up with the title to a book by Niklaus Wirth: Algorithms + Data Structures = Programs.

From GOTO to Object Oriented

Now we have Object Oriented programming languages and a similar paper appeared in communications of the ACM by Ralph Westfall (see reference 2). Declaring that we teach Object Oriented Programming wrong from the very beginning. The quintessential first program in Computer Science is the "Hello World" program. Here Professor Westfall shows us all that we completely miss the opportunity to teach what object oriented programming is all about from the start. It's no wonder kids have trouble with the concepts in AP Computer Science. They teach an old paradigm from the beginning of the course and it carries through until students are forced to make a pardigm shift to Object Oriented programming. Kind of silly when the pardigm has been in force for over 15 years. This is what I had to do as I shifted from C to C++/Java. Only I had a lot more time to do it than 1 year. Infact, much of my early work in C++/Java had very little to do with the new object oriented paradigm. I was just doing structured programming in these new object oriented languages. I had to come to terms with the new paradigm because I was firmly rooted in the "Structured" programming paradigm. But we seem to make the new generation of budding computer scientists become rooted in the old paradigm almost as if it is a rite of passage.

The following code I did from memory it is essentially the same in Dr. Westfall's article and he references the book "The Java Programming Language" as his source:

package apcompsci;
Class HelloWorld {
  static public void main (String[]args)
  {
    System.out.println("Hello World");
  }
}

Simple enough program but as Prof. Westfall points out this is just C style structured programming there is nothing object oriented about it.

Now an object oriented version. I take some liberties to be brief, like including a 'main' method in the class for testing purposes. Prof. Westfall created 2 classes to prove his point. One to implement the class(object) and another to use it. I also improve on the object oriented design from Dr. Westfall's article (he uses a static method which undermines the object orientedness of his original example a bit at least in my opinion).

package apcompsci;
Class HelloWorld {
  String greeting;
  HelloWorld(String s) {
    this.greeting = s;
  }

  // The @Override is to overide an already existing method in the Object class
  // this flags the method for Javadoc and netbeans purposes.
  @Override  
  public String toString() {
    return this.greeting;
  }
  static public void main(String [] args) {
    HelloWorld hello = new HelloWorld("Hello World");

    System.out.println(hello);
  }
}

The output of the above two programs is the same. You wouldn't be able to tell just from the output which one is the object oriented version. But Object Oriented programming isn't concerned with output it is concerned with better program organization to obtain the output. For simple programs the organizational improvement is certainly less impressive. But as you create more complex programs the improvements should be self evident. For what it's worth I believe my programs done in Java are much easier to understand and maintain than any of my previous work done in structured programming languages.

Basic Tenets of Object Oriented Programming: Inheritance, Polymorphism, Encapsulation

Inheritance

I won't go into a long explaination about inheritance except for the fact that the object created above implicitly (meaning the compiler does it for me) inherits from the Java 'Object' Class. So if you have been writing programs in Java you have automatically been using the inheritance features of Object Oriented Programming. As a foreshadowing yet to come (in another blog post) inheritance allows you to take somebody's Object implementation and add to it ('extend' is the Java term) for your own nefarious purposes. But without having to change the code of the original object. This is a great strength of Object Oriented programming and is very helpful on large multi-programmer projects where you need to borrow functionality that has already been tested by another programmer.

Polymorphism

The name is scarier than the actual concept. In fact you may have been making use of it without knowing what it's called. I won't give you a proper definition (I don't feel like adding a reference). But it means that you can reuse method names for different parameters and the compiler will match up the calls based on what the Java 'Class' of the parameter is. The typical example would be an object that performs calculations. You may want to perform the calculation allowing an integer parameter or a double parameter. In this case you define a calc(int i) method and a calc(double d) method. When you go to use your methods for example obj.calc(2) or obj.calc(2.3) the compiler figures out that 2 is an int so use the calc method with an int parameter and that 2.3 is a double so use the method with the double parameter. In the old days you would have to have unique names for each method call which is tedious and confusing since the probably do almost identical calculations.

Encapsulation

Encapsulation includes data hiding. The user of an object should not have to be burdened with the underlying implementation of fields and methods. The maker of an object should publish a set of documentation that explains how to create an object and what messages must be passed to the object to cause the desired functionality to occur.

In the case of the code above we can hide the call to System.out.println. The user of an object should not have to know exactly how to draw it or print it onto the screen. The object should take care of that. Just as we hide data inside the object definition, object oriented programming also says to hide the method (procedures in old Computer Science speak) implementations inside the object as well. Then by sending a message to the object we get the functionality we expect. It's all tied up in a neat little package defined in our Class implementation. So a stricter implementation would be:

package apcompsci;

/**
 *
 * @author nasty
 */
public class HelloWorld {
  String greeting;
  HelloWorld(String s) {
    this.greeting = s;
  }

  public void print() {
    System.out.println(this);
  }

  // The @Override is to overide an already existing method in the Object class
  // this flags the method for Javadoc and netbeans purposes.
  @Override
  public String toString() {
    return this.greeting;
  }

  static public void main(String [] args) {
    HelloWorld hello = new HelloWorld("Hello World");

    hello.print(); // sends a 'print' message to the object
  }
}

This may seem trivial but consider a more complicated project with an object with complex data fields. A 'print' method would be very handy for a programmer to have. Programmers could get meaningful output without having to rely on 'insider' knowledge of the object definition. This is a main feature of encapsulation to hide details inside the object and give programmers a well documented series of method calls in which to do useful things with the object.

Now let's take it a step further. Once I have this HelloWorld object class implemented I am no longer limited to just creating one HelloWorld object. I can create multiple objects each with a different text. Then I can print each one out by sending a 'print' message to each object. In Java we send messages by the following syntax:

<object_name>.<method_name>(<parameters_if_any)

Yes this is just what used to be known as a procedure call but in object oriented programming there is more going on than meets the eye. Under the covers the code is keeping track of what to call and where the definition for that code exists (remember there is something called inheritance that goes on beneath the covers so the code may not even be in your object definition). So now a multi-object version of HelloWorld class would look like:

package apcompsci;

/**
 *
 * @author nasty
 */
public class HelloWorld {
  String greeting;
  HelloWorld(String s) {
    this.greeting = s;
  }

  public void print() {
    System.out.println(this);

  }
  // The @Override is to overide an already existing method in the Object class
  // this flags the method for Javadoc and netbeans purposes.
  @Override
  public String toString() {
    return this.greeting;
  }

  static public void main(String [] args) {
    HelloWorld hello = new HelloWorld("Hello World");
    HelloWorld hi = new HelloWorld("Hi World");
    HelloWorld hello_german = new HelloWorld("Guten Tag Welt!");

    hello.print(); // sends a 'print' message to the object
    hi.print();
    hello_german.print();
  }
}

The output looks like this when run under the Netbeans IDE (IDE stands for Integrated Development Environment ie. the program you use to construct Java programs):

run:
Hello World
Hi World
Guten Tag Welt!
BUILD SUCCESSFUL (total time: 2 seconds)

Improved (or more complicated depending on your perspective) a bit further

package apcompsci;

/**
 *
 * @author nasty
 */
public class HelloWorld {
  String greeting;
  HelloWorld(String s) {
    this.greeting = s;
  }

  public void print() {
    System.out.println(this);

  }
  // The @Override is to overide an already existing method in the Object class
  // this flags the method for Javadoc and netbeans purposes.
  @Override
  public String toString() {
    return this.greeting;
  }

  static public void main(String [] args) {
    HelloWorld hello = new HelloWorld("Hello World");
    HelloWorld hi = new HelloWorld("Hi World");
    HelloWorld hello_german = new HelloWorld("Guten Tag Welt!");

    hello.print(); // sends a 'print' message to the object
    hi.print();
    hello_german.print();

    // Let's use an array of objects and a loop and see what it looks like
    HelloWorld[] hellos = {null, null, null}; // This creates an array of null
    // I need to fill the array with some actual objects
    hellos[0] = hello;
    hellos[1] = hi;
    hellos[2] = hello_german;

    // Now print them in reverse order from the first time
    for (int i = 2; i >= 0; i--) {
        hellos[i].print();
    }
  }
}

The Output:

run:
Hello World
Hi World
Guten Tag Welt!
Guten Tag Welt!
Hi World
Hello World
BUILD SUCCESSFUL (total time: 2 seconds)

Take a good look at the array code above and try to understand it. This could become the start of a section of code to take greetings from a file and turn them into HelloWorld objects. You could then create a program that reads in the file, creates an object for each line of text in the file and then gives you a random greeting from the text you read in. While you may be wondering what is the possible use of something like the code above. Let's just say instead of text these were objects drawn on the screen. This small piece of code could be the start of a drawing program. As you create more and more objects you don't want to be writing out individual variable names for each one do you? No you want to store them in an an array or list and use loops to go through each of the objects to do useful things. Make the computer do all the work so you don't have to.

References

  1. Dikstra, Edgar. “Go To Statement Considered Harmful.” Communications of the ACM 11.3 (1968): n. pag. Print.
  2. Westfall, Ralph. “Hello, World Considered Harmful.” Communications of the ACM 44.10 (2001): 10–11. Print.
  3. Arnold, K. and Gosling, J. "The Java Programming Language" 2nd edition Reading, MA: Addison-Wesley 1997 Print.
  4. Wirth, Niklaus. "Algorithms + Data Structures=programs" Englewood Cliffs, NJ: Prentice-Hall, 1976. Print.

Author: Nasty Old Dog

No comments:

Post a Comment