Purpose of where clause when implementing trait for concrete type

⚓ Rust    📅 2026-01-26    👤 surdeus    👁️ 1      

surdeus

What is the purpose of a where clause in a trait implementation for a concrete type?

While re-reading the book “Rust for Rustaceans” by @jonhoo, I stumbled across listing 2-6 that demonstrates “an excessively generic implementation of Debug for any iterable collection”. As given in the book, the listing reads

impl Debug for AnyIterable
  where for<'a> &'a Self: IntoIterator,
        for<'a> <&'a Self as IntoIterator>::Item: Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_list().entries(self).finish()
}}

The book says:

You could copy-paste this implementation for pretty much any collection type and it would “just work.” Of course, you may want a smarter debug implementation, but this illustrates the power of trait bounds quite well.

I believed to have understood that trait bounds are used in generic programming to specify the required capacities of a generic type. But in the above example everything is concrete - how would this serve as a demonstration of the power of trait bounds?

Here is a complete program that includes the above snippet, applied to SomeIterable. And, sure enough, it compiles with the where clause commented out:

struct SomeIterable(Vec<String>);

impl<'a> IntoIterator for &'a SomeIterable {
    type Item = &'a String;
    type IntoIter = std::slice::Iter<'a, String>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.as_slice().into_iter()
    }
}

use std::fmt::{Debug, Error, Formatter};

impl Debug for SomeIterable
// where
//     for<'a> &'a Self: IntoIterator,
//     for<'a> <&'a Self as IntoIterator>::Item: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_list().entries(self).finish()
    }
}

fn main() {
    let v = vec![String::from("hello"), String::from("world")];
    let v = SomeIterable(v);
    dbg!(&v);
}

I must be missing something obvious here, so I hesitated to bother this friendly forum. But unfortunately, I was not able find any discussion of this topic – neither here, nor elsewhere on the web, nor in books that I have.

Is the purpose only to serve as a form of “static typing for a template”, i.e. to provide clearer error messages when the snippet is used for some type in the wild that does not qualify?

6 posts - 4 participants

Read full topic

🏷️ Rust_feed