Extending {} with fmt::Display


#1

time::Duration cannot be printed with “{}” so I tried extending it like this:

impl fmt::Display for time::Duration {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result

But it doesn’t work:

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types

The error message is clear enough, but I was wondering why this isn’t allowed. It would seem useful.

Thanks!


#2

This is known as trait coherence. In a nutshell, you can impl foreign traits for your own types or local traits for foreign types. I’m on mobile or else I’d link some reading material for you. But you can search that phrase and get some hits.

The workaround here is to newtype Duration and impl Display for that.


#3

Thanks!


#4

To explain a bit the motivation for this rule: if you were allowed to implement Display for Duration, then adding such an implementation to the standard library later on would be a breaking change, because it would conflict with your code. This would severely limits the extent to which the standard library can evolve without breaking existing Rust code.

More generally, a problem could also appear if two crates which implement Display for Duration were linked together in a single application.

Of course, we could imagine ways to work around this, based around the idea of giving priority to “local” implementations over “external” ones. But going in this direction would make the language less predictable and more surprising.