I would like to emphasize that these two issues are really orthogonal: “printing some data for debug purposes” is about defining new functions, while “overloading operators” is about figuring out which existing functions to use at a given type.
Only the latter is solved by type classes/traits/implicits. For the former, PPX is used today, but it is an imperfect solution (mostly because it is syntactic and separate from the compiler). It corresponds to the “deriving” mechanism found in Haskell or Rust.
Personally, I think that in terms of sheer utility it is the latter, having a built-in deriving mechanism, that is much more useful than having type classes/implicits (which allow overloading). See also this related thread: