src/idiomatic/polymorphism/refresher/conditional-methods.md
# // Copyright 2025 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
// No trait bounds on the type definition.
pub struct Value<T>(T);
// Instead bounds are put on the implementations for the type.
impl<T: std::fmt::Display> Value<T> {
fn log(&self) {
println!("{}", self.0);
}
}
// alternatively
impl<T> Value<T> {
// Specifies the trait bound in a where expression
fn log_error(&self)
where
T: std::error::Error,
{
eprintln!("{}", self.0);
}
}
When authoring a type with generic parameters, we can write implementations for that type that depend on what the parameters are or what traits they implement.
These methods are only available when the type meets those conditions.
For things like ordered sets, where you'd want the inner type to always be
Ord, this is the preferred way of putting a trait bound on a parameter of a
type.
We don't put the definition on the type itself as this would cause downstream issues for everywhere the type is mentioned with a generic parameter.
We can maintain invariants just fine with conditional method implementations.