DEV Community

pintuch
pintuch

Posted on

1

Rust - my dumbness with grokking impl<T>

The first time I came across code like this

impl<T> MyTrait for MyStruct<T> {...}
Enter fullscreen mode Exit fullscreen mode

I had wondered why must the generic type T show up next to both the impl as well as MyStruct. Wasn't MyStruct<T> enough to convey the intent?

I had my aha! moment today while working on a program that looked something similar to this:

struct MyStruct<T> {
    x: T    
}

trait Bogus {
    fn do_nothing(&self);
}

// missed the `impl<T>`
impl Bogus for MyStruct<T> {
    fn do_nothing(&self) {
        println!("do nothing")
    }
}

// somewhere way down in the code
type T = i32;

Enter fullscreen mode Exit fullscreen mode

Out of habit, I had missed the type parameter T next to the impl keyword. The code still managed to compile.

Later, I noticed what had happened. So, did I end up implementing the Bogus trait for the generic MyStruct<T> or was it for MyStruct<i32>? As you might have already guessed, it's the latter.

It was now so obvious that the T next to impl serves the purpose of disambiguation. The compiler can't just assume it's a generic type just because the type declaration isn't immediately in our focus.

// implement Bogus Trait for MyStruct<T> where T could be any type
impl<T> Bogus for MyStruct<T> {
    fn do_nothing(&self) {
        println!("do nothing")
    }
}

// implement Bogus Trait for MyStruct<T> where T is a type declared somewhere
impl Bogus for MyStruct<T> {
    fn do_nothing(&self) {
        println!("do nothing")
    }
}

Enter fullscreen mode Exit fullscreen mode

I feel so dumb that it took me so long to grok something so obvious!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (1)

Collapse
 
rsalmei profile image
Rogério Sampaio de Almeida

That initial <T> declaration is actually read as "For any type T...". And that's why it supports trait bounds there, an impl<T: Clone + Send> means "For any type T that also implements Clone and Send..." 😉

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay