This post is going to focus on the basics of object-oriented programming, including polymorphism and dynamic method dispatching. I will use Python for illustrating these concepts.

Here's a very basic Shape class. Each Shape has a method contains() that returns True if the shape contains a given point, and returns False otherwise.

class Shape:
  def contains(self, x, y): 
    return False

Python class definitions start with the class keyword, then the class name.

In most object-oriented languages (including C++, Java, and JavaScript) a method can refer to its object with the keyword this. Python takes an unusual approach of explicitly passing the object as the first parameter to the method. So, for the contains() method, the parameter self refers to the Shape object. In the code below:

x = Shape()
x.contains(0, 0)

x is a Shape object, and contains() gets called with the Shape x passed to the variable self, and the value 0 passed to the variables x and y.

Since a shape that contains no points isn't very interesting, lets create a rectangle class. In Python, inheritance is done by putting the name of the parent class in parentheses after the name of the new class.

class Rectangle(Shape):
  def __init__(self, x, y, width, height):
    self.x=x
    self.y=y
    self.width=width
    self.height=height
  def contains(self, x, y):
    return x >= self.x and y >= self.y and x <= self.x+self.width and y <= self.y + self.height

Each Rectangle has x and y coordinates for its top left corner, and has a width and height. The Rectangle class overrides the contains() method to test whether the given point is in fact inside the rectangle.

What can we do with this? Let's write a function that tests a grid of points against a given shape, and uses that information to draw that shape!

def prettyPrint(shape):
  for line in range(30):
    for column in range(80):
      if shape.contains(column, line): 
        sys.stdout.write('#')
      else: 
        sys.stdout.write(' ')
    sys.stdout.write('\n')

This code draws out an area eighty characters wide and thirty characters tall. It draws a # symbol in each slot inside the shape, and an empty space in each slot outside the shape. Let's call this function with a Rectangle:

>>> prettyPrint(Rectangle(10, 5, 20, 10))
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                             
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################
          #####################





That looks like a rectangle to me!

Now, let's try another kind of shape: a circle.

class Shape:
    def __init__(self, x, y, radius):
            self.x=x
            self.y=y
            self.radius=radius
    def contains(self, x, y):
            return ((self.x-x)**2 + (self.y-y)**2) <= self.radius**2

Each Circle has the coordinates of its center, and a radius. Again, contains() is overridden. In this case, it simply tests whether the point lies inside the circle by comparing (self.x-x)2 + (self.y-y)2 against the square of its radius.

So, let's try prettyPrint() with a Circle:

>>> prettyPrint(Circle(10, 10, 10))
                                                                                
      #########                                                                 
     ###########                                                                
   ###############                                                              
   ###############                                                              
  #################                                                             
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
 ###################                                                            
  #################                                                             
   ###############                                                              
   ###############                                                              
     ###########                                                                
      #########                                                                 
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                

Again, looking good. The circle looks a little stretched because each # is a little taller than it is wide, but it's still recognizably a circle.

So, where does the polymorphism and dynamic method dispatching come in?

We see polymorphism in the prettyPrint() function. The shape variable can be either a Square or a Circle (polymorphism literally means "many shapes"!). prettyPrint() doesn't have to know what type of Shape it has, and it doesn't care.

Dynamic method dispatching comes in when prettyPrint() calls contains(). The code doesn't decide up front which version of contains() we need to call. It waits until the call happens, checks what kind of Shape we have, and dynamically dispatches the call to the correct function.