A search on this topic generates several hits that quickly get me to explaining why
impl<T> fmt::Display for T where T: TraitWithDisplaySupport
... won't compile. The reason seems to be the less-intuitive need to consider a "forward-looking" view that prevents the mere possibility of conflicting implementations of the std::fmt::Display
trait.
Notwithstanding, the expressiveness of the trait system is getting better and better. In that context, some of the responses seem dated relative to the pace of the trait improvements.
I've benefited a great deal from this online community. In that spirit, I thought I would share an amalgamation of what I've learned and "gotten through" the compiler.
With some input and comments, I thought it might serve as a complete inventory of options to this often requested capability.
how to provide display support for the consumer of MyTrait
.
I implemented 3 approaches to leverage MyTrait
to provide a unified, default Display
capacity. Based on what I suspect are gaps in my understanding of GATs and type annotations, useful alternatives beyond what is here may well exist.
fn main() {
// A implements MyTrait
let a = A {/*..*/}
// option 1
// A implements Display using a MyTrait default display function
println!("{}", &a);
// option 2
// MyTrait uses a "go-between" struct that implements Display
println!("{}", &a.as_display());
// option 3
// Cast A to the MyTrait that implements Display
println!("{}", &a as &dyn MyTrait);
}
Questions:
-
Are there other approaches?
-
Are there ways to improve the ergonomics by implementing other traits that exploit some of the casting and coercing that happen behind the scenes in Rust? (e.g., similar to implementing
Deref
for the "newtype" pattern to access the capacity of the underlying type?) -
Do generic associated types (GATs) provide a way to solve "forward-looking" potential for collisions during monomorphizations (duplicate implementations)?