Inheritance and Composition

Last Time: OOP

  • Group related data and functions together
  • Don't worry about how something happens, just worry about what happens.

One of the manifestations of these ideas is Object Oriented Program. Create compound structures consisting of multiple members.

 

Data members referred to as fields.

Function members referred to as methods.

Classes and Objects

Classes form the blueprint for

data and functions.

Objects are concrete realizations of a class.

  • Name: Car
  • Fields:
    • make
    • model
    • color
    • speed
    • fuel
  • methods:
    • accelerate(rate)
    • brake(rate)
  • Name: car_7
  • Fields:
    • make = "Honda"
    • model = "Civic"
    • color = PURPLE
    • speed = 0
    • fuel = 10.0

How to Create Classes + Objects

class Spot {
  float x, y, radius;
  
  void display() {
    ellipse(x, y, radius, radius);
  }
  
  Spot(){
    x = 50.0;
    y = 50.0;
    radius = 30.0;
  }
  
  Spot(float x, float y, float r) {
    this.x = x;
    this.y = y;
    this.radius = r;
  }
}
Spot sp1, sp2;

void setup(){
  sp1 = new Spot();
  sp2 = new Spot(75, 80, 15);
}

void draw(){
  sp1.display();
  sp2.display();
}

Code Review

Questions

How do you know when to use classes vs. using functions?

This is definitely a matter of taste, style, and experience.

 

General rule: if there are multiple data that should be operated on together, bundle into a class.

What are the disadvantages of OOP? What's the new thing?

Complexity of subtyping relations (which we will briefly discuss today).

Industry as a whole has been swinging towards functional programming in the last 10 years, but many things are simply not possible (or very difficult) in  a functional setting.

Can we reuse classes between code?

Yes. In fact, I highly encourage you to do so, although creating truly reusable classes is hard and so you'll probably have a little trouble at first.

Processing treats a .pde file with the same name as the folder as the "primary" PDE file. All other .pde files within the directory are assumed to be for classes.

The ability to design reusable code comes through trying to reuse nonresuable code!

How can we provide default arguments to constructors?

class A {
  float x, y;
  
  A(float x){
    this(x, 1.0);
  }
  
  A(float x, float y){
    this.x = x;
    this.y = y;
  } 
}

void setup(){
  A a1 = new A(1.0);
  A a2 = new A(2.0, 2.0);
}

Java will select the version to use based off of number and type of arguments.

Also works for regular functions and methods!

In this sense, a constructor is like a special method that returns a new instance of the class (i.e. a new object).

Any other famous Minecraft bugs?

What alternative to creating sparks are there?

A technique commonly called "object pooling". Instead of creating and deleting a bunch of objects, keep a pool of them on hand but don't display them.

Do we need to worry about memory allocation in Processing?

How many classes can be used within each other before program speed starts to suffer?

How many classes can be used within each other before program speed starts to suffer?

Modern computers are fast.

Languages like Python simply weren't used in the 90s because they were too slow!

Combinatorial explosions (e.g. \( 2^n \) runtimes) can bring even the fastest computer to its knees, but unless you're working with giant data (\(N \geq 10^{10} \)), minor overheads simply aren't going to matter.

Relating Classes to Each Other

The ability to bundle related data and functions together is nice, but can be obtained with other tools as well. In Python, we could use dicts, sets, and modules to bundle code/variables together.

The true power of OOP lies in the ability to specify relationships between classes (and thus between objects).

Composition

Suppose we are trying to design a Bike class. What pieces might we need for this class?

  • Frame
  • Wheels
  • Brakes
  • Drivetrain
  • Handlebars

In English, we would say that "a bike has a frame". This is the has-a relation, or composition.

Animating a Bicycle

To animate:

  • Bike must move
  • Wheels must rotate

 

Additional rule: wheels on front and back must be the same model.

class Bicycle{
  Frame frame;
  Wheel frontW;
  Wheel backW;
  float x, y;
  float wheelDist;
  
  Bicycle(Frame f, Wheel w){
    // Initialize bike
  }
  
  void displayBike(){
    // ?
  }
  
  void moveBike(float dx){
    // ?
  }
}
void displayBike() {
  frame.drawAt(x, y);
  frontW.drawAt(x+wheelDist/2, y);
  backW.drawAt(x-wheelDist/2, y);
}
void moveBike(float dx) {
  this.x += dx;

  // Why can we compute one rotation for both?
  float wheelRotation = dx / (Math.PI * frontW.diameter);
  
  frontW.rotate(wheelRotation);
  backW.rotate(wheelRotation);
}

Note: we don't have to do 100% of the work ourselves! Delegate work to components.

Why Use Composition?

Allow us to break complex problems into simpler ones.

 

Don't need to know how to draw the entire bike: just have to know where to draw the wheels and let the wheels draw themselves!

We can ignore how certain things are implemented.

 

How is Wheel::rotate() implemented? Don't know. Don't care!

Inheritance

Suppose we are trying to model multiple forms of transport vehicles. What classes do we have?

  • Bike
  • Car
  • Truck
  • Scooter
  • Skateboard

Has-a isn't really appropriate to describe the relationship between these!

Hierarchical Description

Vehicle

Motorized Vehicle

Human-Powered Vehicle

Scooter

Car

Bus

Bicycle

Skateboard

What might we call these arrows?

  • A class can inherit from another class.
    • The class that inherits is known as a subclass, derived class, or child class.
    • The class that is inherited from is know as a superclass, base class, or parent class.
  • A subclass extends a superclass. It contains all the fields and methods of the superclass, but can also be extended with more.

An example of an is-a relationship.

A car does not contain a motorized vehicle, it is a motorized vehicle. It can do everything a motorized vehicle can and more.

Motorized Vehicle

Car

Bus

class MotorizedVehicle {
  float fuel, speed;
  void addFuel(float amount){ /* */ }
  void accelerate(float rate){ /* */ }
}

class Car extends MotorizedVehicle {
  color color;
}

class Bus extends MotorizedVehicle {
  int numSeats;
}
Car myCar = new Car();
myCar.color = color(10, 20, 30);
myCar.addFuel(10.0);
myCar.accelerate(20.0);
  • Use extends keyword to declare that a class is a subclass of another.
  • Subclass declares members that are not in the superclass
  • Still has access to superclass members!

Hmmmm.....

Constructors in Inheritance

class MotorizedVehicle {
  float fuel, speed;
  void addFuel(float amount){ /* */ }
  void accelerate(float rate){ /* */ }
  
  MotorizedVehicle(float fuel){
    if (fuel < 0){
      // ERROR: Fuel cannot be negative!
      this.fuel = 0.0;
    } else {
      this.fuel = fuel;
    }
    this.speed = 0.0;
  }
}

When writing a constructor, construct the parent class by calling super().

class Car extends MotorizedVehicle {
  color color;
  
  Car(color c, float fuel){
    super(fuel);
    this.color = c;
  }
}

Subclass Relations + Overriding

class MotorizedVehicle {
  float fuel, speed;
  void addFuel(float amount){ /* */ }
  void accelerate(float rate){ /* */ }
}

class Car extends MotorizedVehicle {
  color color;
}

class Bus extends MotorizedVehicle {
  int numSeats;
}

Suppose we have a MotorVehicle object. What can we do with it?

void doAThing(MotorVehicle v){
  // What can we do to v?
}

What if v is a Car or a Bus?

Since a Car is a MotorizedVehicle, anywhere that we expect a MotorizedVehicle, we can use a Car instead!

void doAThing(MotorVehicle v){
  // Check fuel
  if (fuel == 0){
    v.addFuel(10);
  }
  v.accelerate(5);
}
MotorVehicle v1 = new MotorVehicle();
Car c1 = new Car();
Bus b1 = new Bus();

doAThing(v1);
doAThing(c1);
doAThing(b1);

MotorVehicle v1 = new Car(); // Tricky

Note that the opposite is not true!

void doThing2(Car c){ /* ... */ }

MotorVehicle v1 = new MotorVehicle();
doThing2(v1); // ERROR

What if we implement a method in the derived class that has the same name/types as one in the base?

class Foo {
  ...
  void printHello() {
   print("Hi I'm Foo");
  }
}
class Bar extends Foo {
  ...
  void printHello() {
   print("Hi I'm Bar");
  }
}
Foo f = new Foo();
Bar b = new Bar();
f.printHello();
b.printHello();

The method in the child class overrides the one in the parent!

Example of Overrides

class MotorizedVehicle {
  float fuel, speed;
  void addFuel(float amount){ 
    fuel += amount;
  }
  void accelerate(float rate){ 
    this.speed += rate;
    this.fuel -= 0.01 * rate;
  }
}

Motor Vehicles consume fuel to accelerate.

class Bus extends MotorizedVehicle {
  int seats;
  void accelerate(float rate){ 
    this.speed += rate;
    this.fuel -= seats * 0.01 * rate;
  }
}

Buses need to consume more fuel the more seats they have.

void goGoGo(MotorVehicle v){
  v.accelerate(100);
}

Do we know what class v actually is?

Do we need to worry about acceleration being incorrect (i.e. we need to do something to v to make it "work"?)

Don't Mix The Relations!

Warning

People sometimes get confused about the difference between is-a and has-a and model their problem with OOP incorrectly. This leads to what has sometimes been called "certifiably insane" designs.

Real life examples from people who really should have known better:

Car inherits from ParkingGarage because parking garages contain cars

Person should multiple-inherit* from Head, Body, Arm, and Leg

* Multiple Inheritance is a feature that does not exist in Java or Processing

CarWithBumperSticker is a subclass of Car

A circle inherits from a point because I need to show off inheritance for this textbook

Example: ColorSpot

You may want to pull out your laptops and follow along, since some of this will be on the hands-on.

Hands-On: ColorSpot Class

  1. Get the Spot subclass ColorSpot working in your code.
  2. Create another Spot subclass called TwoSpots. (Dropdown > New Tab). TwoSpots displays two ellipses around a center point.
  3. Write code that lets you move a TwoSpots object to a specific location. Do this without modifying the TwoSpots class directly.

Index Cards!

  1. Your name and EID.
     
  2. One thing that you learned from class today. You are allowed to say "nothing" if you didn't learn anything.
     
  3. One question you have about something covered in class today. You may not respond "nothing".
     
  4. (Optional) Any other comments/questions/thoughts about today's class.

[07a]: Components and Inheritance

By Kevin Song

[07a]: Components and Inheritance

  • 76