Introduction to OO

Historical Perspective

Object-oriented programming was a major conceptual change in the 80s and 90s.
Simula, Algol, Smalltalk were early O-O languages
C++ was born from the language ‘C’. Objective-C was as well (and is now used for IPhone programming).
Java was born

Grouping Data

Our brains can only handle 7 +- 2 things at a time.  So we must create abstractions and think hierarchically.
Function allow us to create an abstraction for a sequence of operations.

We also need to abstract groupings of data. We call such groupings ‘complex data types’ or ‘classes’. 

Consider a social network site. What data might be recorded for each person in the system? What data might be stored for a Google search result? For a pixel?

For the Mastermind program, the partialMatches and exactMatches were data that could have been grouped together. We could have defined a class 'Feedback'.

Grouping Data in Python: Classes

How would you represent a 'Person' in Python?
Lists don’t really help define a 'person' it consists of related but heterogeneous data. You really want to name each part, e.g., person.lastName, person.firstName, etc.

The class construct allows a programmer to create data abstractions.
Python uses similar syntax to a function def for a class definition. Inside the class definition you can provide functions  that work on the data of the class. One special such function is a constructor and its always named, __init__ (two underscores, 'init' and two more underscores). A constructor initializes the fields (components) of a class instance. It is indented within the class definition:
    class Person:   # class definition
         def __init__(self):

Once you define a class, you can create instances of it. We call these instances objects. You create them with an object creation statement, then set the fields of the object using dot (.) notation.
    # main
    p1 = Person()                          # this creates a Person object with name="unknown" and age=0
    p2 = Person()                          # this creates a Person object with name="unknown" and age=0
    print p1.age                            # prints 0
    p1.age=34                              # change the age of the object named p1"Joe Williams"        # change the name of the object named p1"William Jones"      # change the name of the object named p2
    p2.age=22                              # change the age of the object named p2
Formally, object creation statements are of the form:
    <object name> = <nameOfClass>()

Field assignment statements use "." to choose the field to modify or access:
In the code above, Person is a class.
p1 and p2 are instances of the class Person.
p1 and p2 are objects of type Person. The terms 'instance' and 'object' are synonymous.
name and age are fields of the class Person. Fields are also called data members.
A class can also have other functions besides __init__ defined within it (we’ll revisit this later).

Instructor Demo

Write a class Feedback and show how it could be used in the Mastermind program.

In-Class Assignment

1. Write a class 'Coordinate' with two fields, x and y. Provide an __init__ method which initializes x and y to zero (create the __init__ function similar to the Person class above).
2. Write a function 'distance' which accepts two coordinates as parameters and returns the distance between them. This function should be defined after the class definition (non-object-oriented) and should have a header that looks like:

    # distance returns the distance from coordinate1 to coordinate2
    def distance(coordinate1,coordinate2):
The formula for distance is:
          The distance between (x1, y1) and (x2, y2) is given by
d=\sqrt{(\Delta x)^2+(\Delta y)^2}=\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}.\,
You may use Python's Math Module and in particular: ‘sqrt’, and ‘pow’.

3. Write a main program to test your class and function. The main program should create two coordinates in a manner similar to how 'joe' and 'bill' were created above. It should then call the function distance, sending the two coordinate objects as parameters. Finally, it should print the coordinates and the distance between them.

Object-Oriented Functions

In the discussion above, we discussed programmer-defined types and used Python classes to represent them.

We didn't really write an object-oriented function except for __init__ (the constructor).
In the world of object-oriented programming, a class is really two things:
             data fields  + functions that work on that data
In other words, we want to organize our program by grouping each data type along with the specific functions that access and manipulate that data. For class Coordinate, we should make the function distance subordinate to the class as it works on a coordinate.
    class Coordinate:
           # note indentation...
           def distance(self,point2):         # note the indentation
                # code for distance

The first formal parameter in an object-oriented function is, by convention, called self. It is the 'subject' of the function, the key piece of data.

When functions are defined subordinate to a class, we call them using the form:  

     <object>.<function> (params)
For example,
    point1 = Coordinate()
    point2= Coordinate()
    dist = point1.distance(point2)

The last line is an object-oriented function call. point1 is the object of the call. It is mapped to the first formal parameter self. point2 is just a regular parameter and maps to the second formal parameter, also named point2.

Effectively, an object-oriented call:

    dist = point1.distance(point2)

is just syntactic sugaring for:

    dist1 = distance(point1,point2)

But you must call it in the object-oriented way if the function is defined subordinate to the class.

In-Class Worksheet

1. Copy your coordinate program into another file,
2. Rewrite the code so that distance is a function inside the Coordinate class. Rewrite the main so that distance is called in an object-oriented manner.
3. Write a class Person with fields name and friend_list, and functions add_friend, list_friends, and get_friend_of_friends. Here are the headers for these functions:

    # add_friend adds the Person friend to self's list of friends
    def add_friend(self,friend):

    #list_friends prints the name of all self's friends
    def list_friends(self):

    # get_friends_of_friends returns a list of Person objects who are friends of self's friends but not self's friends.
    def get_friends_of_friends(self):

  Write a main program that creates some Person objects, adds some friends to each person, and then prints out the friends of friends correctly.