↓ Skip to main content

Learning about Rust types and dynamic dispatch

·289 words

So I had some code very similar to the following that wouldn’t compile and me with my old Python head was a bit surprised why this was the case. It was a bit more complicated to figure it out in my example but this simplified version makes it pretty clear.

trait SomeTrait {}

impl SomeTrait for u8 {}
impl SomeTrait for u16 {}

fn function() -> impl SomeTrait {
    if true {
        0u8
    } else {
        0u16
    }
}

Why did I think it would work? Because both types implement the same trait, it’ll come down to the same thing in the end and that should be fine, right? I think that’s Python talking.

The Rust compiler needs to know how much space every function’s return type requires.

https://doc.rust-lang.org/rust-by-example/trait/dyn.html

Let’s think about it from a Rust perspective which means think about the memory layout of this. We’re on the stack here and in this case it may only be a difference of a byte, it’s very possible to have two vastly different types implement the same trait. That can’t possibly work.

The answer then of course is to:
1. Move things into the heap with `Box. That doesn’t fully solve it because then both arms have a different type Box<u8> and Box<u16> respectively. But crucially now they’re always the same size.
2. Change the return type to a trait object that both types conform to with dyn.

trait SomeTrait {}

impl SomeTrait for u8 {}
impl SomeTrait for u16 {}

fn function() -> Box<dyn SomeTrait> {
    if true {
        Box::new(0u8)
    } else {
        Box::new(0u16)
    }
}

This works and is dispatched dynamically.

Thanks by the way to the people in the Tokio Discord for being extremely patient with me.

Alper Cugun
Author
Alper Cugun

Related

·128 words
I agree with this take by Jacob Kaplan-Moss that you should be able to estimate very accurately and then just not do it most of the time. Learning how to estimate is a non-negotiable part of building an intuition for software engineering. It’s not the estimation that we need, it’s the intuition.

Improving the way we do posts is something I’ll be spending a bunch of attention on in the next months and here is an excellent guide of how to improve that part of the incident process.

·107 words
That’s a very astute observation of the state and culture of the Go programming language. I got out of Go way before I hit anything like this (though the Channel Axioms are something everybody is going to deal with). For me Go is a not very interesting intermediary language between Python and Rust.