case-studies
case-studies copied to clipboard
Inherent method specialization
Thanks for writing up the autoref specialization guide!
There's a similar technique which depends on Rust favoring inherent impls over traits.
Taking the DisplayToString example:
use std::fmt::{Display, Write};
pub trait DisplayToString {
fn my_to_string(&self) -> String;
}
pub struct DisplayToStringWrapper<'a, T: ?Sized>(pub &'a T);
// This is an inherent method, so it's tried first
impl<'a, T: AsRef<str> + ?Sized> DisplayToStringWrapper<'a, T> {
pub fn my_to_string(&self) -> String {
println!("called specialized impl");
self.0.as_ref().into()
}
}
// This is only used if the inherent method fails to type-check
impl<'a, T: Display + ?Sized> DisplayToString for DisplayToStringWrapper<'a, T> {
fn my_to_string(&self) -> String {
println!("blanket impl");
self.to_string()
}
}
This can be more reliable than the autoref approach. For example, (&&String::from("hello")).my_to_string() will fall back to the slow path using autoref specialization but stick to the fast path with inherent impls. The drawback is that it only allows for one fallback case. Overall, I think this approach makes some interesting tradeoffs and may be worth calling (hehe) out in the article!