Walking through "The Java Tutorials" with Rust

Polymorphism with the 'dyn' keyword and Trait Objects

A tired evening in June 2021

In the previous page I showed that simply declaring a variable and assigning different types at runtime isn't possible, technically because the complier wants to know the type of the declared local variable.

Apparently, the thing that is absolutely necessary in compile time is that the size of the variable would be known so it could be allocated and removed from the stack.

Another thing that the type defines is what methods are available for that type. Usually, methods are known in compile time, but one can opt out from this behavior and postpone the methods resolution to runtime with the dyn keyword. Declaring a variable as dyn Bicycle instructs the complier to create a virtual table for that variable, and this table could be populated during runtime with addresses of the correct methods to run. This is called Dynamic dispatch.

Let's demonstrate how to write the example above following an approach similar to Rust Design Patterns - On-Stack Dynamic Dispatch:

fn random_bike() {
    // this time we will get a random bike at runtime!
    let coin : bool = rand::random();

    // we have to declare these in advance
    // `bike` below will point to either basic or mountain 
    let (mut basic, mut mountain);

    // &dyn Bicycle is a reference to something that implements the Bicycle trait
    let bike: &mut dyn Bicycle = if coin {
        basic = BasicBicycle { cadence: 0, speed: 0, gear: 0};
        &mut basic
    } else {
        mountain = MountainBicycle { cadence: 0, speed: 0, gear: 0, tires: "mountain tires".to_string()};
        &mut mountain
    };

    bike.speed_up(123);
    bike.print_states();
}

Notice that because bike is a reference, it's size is known at compile time (to be some pointer size), and it points to the space allocated for basic or mountain.

We can go a step further and eliminate the need to allocate space for the different Bicycle types by moving to from the stack to the heap. In the next page we'll try to use the Box struct to hold the dynamically allocated bike inside it.