---
# System prepended metadata

title: Dynamic Method Selection (Method Lookup)
tags: [Berkeley, CS61B]

---

# Dynamic Method Selection (Method Lookup)
Author: Cliff Liu (cliffliu@berkeley.edu)
*Please contact me if you have any questions or feedback!*
###### tags: `CS61B` `Berkeley`

## Step 1: Compile-Time
Do assignment statements check out, as in there is an **is-a** relationship between the RHS and LHS. Think of LHS as a container. Does RHS fit into the LHS container?
- If yes, move on to step 2.
- If not, then Compile-Time Error.

## Step 2: Compile-Time
Does the **static** type class of the object have the correct method signature? As in, does there exist a method in the **static** class that has the same *method name* and same **static** *parameters*?
- If yes, then the compiler will **lock in** this matching method.
- If not, then do the following check:
    - Is the static parameter class a subclass^1^ of another class?
        - If yes, call the parent class the ==superclass==. Then do the same check: does there exist a method in the **static** class that has the same *method name* that takes in the ==superclass== as a parameter? If so, this method is **locked in**.
        - If not, then Compile-Time Error.

## Step 3: Runtime
Does the **dynamic type** class of the object have a method signature that **overrides** the **locked in** method from compile time?
- If yes, then we use the dynamic method we just found instead.
- If not, use the **locked in** method from compile-time instead.

## Examples + Walkthrough
Suppose we have a Dog class and a Poodle class that extends Dog:
```java 
class Dog {
    void bark(Dog d) {
        System.out.println("bark");
    }
}

class Poodle extends Dog {
    void bark(Dog d) {
        System.out.println("woof");
    }

    void bark(Poodle p) {
        System.out.println("yap");
    }

    void play(Dog d) { 
        System.out.println("no"); 
    }

    void play(Poodle p) {
        System.out.println("bowwow");
    }

    public static void main(String[] args) {
        Dog dan = new Poodle(); 
        Poodle pym = new Poodle(); 
    }
}
```
We instantiated dan with static type Dog and dynamic type Poodle.
We instantiated pym with static type Poodle and dynamic type Poodle.
Since a poodle "is-a" dog and a poodle "is-a" poodle, the RHS fits into the LHS container for both instances. As a result, we do not Compile-Time Error for any of these assignment statements.

Moving forward, we will only need to check steps 2 and 3, since we already confirmed step 1 will not Compile-Time Error. Also, all of the explanations are independent of one another. Feel free to skip around between the examples as they are ran independently of one another.

#### Example 1: Suppose we make the following function call: 
```java
dan.play(dan);
```

In step 2, we check whether the static type of dan (Dog) has a play method that takes in the static type of dan (Dog). It does not, so **Compile-Time Error**.

#### Example 2: Suppose we make the following function call: 
```java
dan.play(pym);
```

In step 2, we check whether the static type of dan (Dog) has a play method that takes in the static type of pym (Poodle). It does not, so **Compile-Time Error**.

#### Example 3: Suppose we make the following function call: 
```java
pym.play(dan);
```

In step 2, we check whether the static type of pym (Poodle) has a play method that takes in the static type of dan (Dog). It does, so the compiler locks in that method. In step 3, we check whether the dynamic type of pym (Poodle) has a play method that overrides the locked in method (play that takes in a Dog). Yes, it turns out this is the same method that we locked in, so we run this and print **no**.

#### Example 4: Suppose we make the following function call: 
```java
pym.play(pym);
```
In step 2, we check whether the static type of pym (Poodle) has a play method that takes in the static type of pym (Poodle). It does, so the compiler locks in that method. In step 3, we check whether the dynamic type of pym (Poodle) has a play method that overrides the locked in method (play that takes in a Poodle). Yes, it turns out this is the same method that we locked in, so we run this and print **bowwow**.

#### Example 5: Suppose we make the following function call: 
```java
pym.bark(dan);
```
In step 2, we check whether the static type of pym (Poodle) has a bark method that takes in the static type of dan (Dog). It does, so the compiler locks in that method. In step 3, we check whether the dynamic type of pym (Poodle) has a bark method that overrides the locked in method (bark that takes in a Dog). Yes, it turns out that this is the same method that we locked in, so we run this and print **woof**. 

#### Example 6: Suppose we make the following function call: 
```java
pym.bark(pym);
```
In step 2, we check whether the static type of pym (Poodle) has a bark method that takes in the static type of pym (Poodle). It does, so the compiler locks in that method. In step 3, we check whether the dynamic type of pym (Poodle) has a bark method that overrides the locked in method (bark that takes in a Poodle). Yes, it turns out that this is the same method that we locked in, so we run this and print **yap**.

#### Example 7: Suppose we make the following function call: 
```java
dan.bark(dan);
```
In step 2, we check whether the static type of dan (Dog) has a bark method that takes in the static type of dan (Dog). It does, so the compiler locks in that method. In step 3, we check whether the dynamic type of dan (Poodle) has a bark method that overrides the locked in method (bark that takes in a Dog). It does, so we call the overridden method instead and print **woof**.

#### Example 8: Suppose we make the following function call: 
```java
dan.bark(pym);
```
In step 2, we check whether the static type of dan (Dog) has a bark method that takes in the static type of pym (Poodle). It does not, however, Poodle is a subclass of Dog! (See Footnote 1). Since the static type of dan (Dog) has a bark method that takes in the superclass of Poodle (Dog), we lock in the bark(Dog d) method. In step 3, we check whether the dynamic type of dan (Poodle) has a bark method that overrides the locked in method (bark that takes in a Dog). It does, so we call the overridden method instead and print **woof**.


## Footnotes:
1: In reference to a superclass, the compiler will keep checking as long as a superclass exists. For example, if we had the following relationship: A --> B --> C --> D, where x --> y means that y extends x, then we will keep checking whether C, then B, then A is a static parameter.