To_debug, a Debug counterpart of to_string

The ToString trait provides a shorthand object.to_string(), equivalent to using Display to format the object as a string.

Several times lately, I've found myself wanting an equivalent shorthand that uses Debug to format the object as a string.

Does it seem reasonable to add a method like to_debug for that?

1 Like

It would need to be a separate trait from ToString, right?

Yes. It would look something like this:

/// A trait for converting a value to a `String` via [`Debug`].
/// This trait is automatically implemented for any type which implements the
/// [`Debug`] trait. As such, `ToDebug` shouldn't be implemented directly:
/// [`Debug`] should be implemented instead, and you get the `ToDebug`
/// implementation for free.
/// [`Debug`]: ../../std/fmt/trait.Debug.html
#[unstable(feature = "todebug", reason = "new API", issue="...")]
pub trait ToDebug {
    /// Converts the given value to a `String` via `Debug`.
    /// # Examples
    /// Basic usage:
    /// ```
    /// let s = "hello";
    /// let hello = String::from("\"hello\"");
    /// assert_eq!(hello, s.to_debug());
    /// ```
    #[unstable(feature = "todebug", reason = "new API", issue="...")]
    fn to_debug(&self) -> String;

/// # Panics
/// In this implementation, the `to_debug` method panics
/// if the `Debug` implementation returns an error.
/// This indicates an incorrect `Debug` implementation
/// since `fmt::Write for String` never returns an error itself.
#[unstable(feature = "todebug", reason = "new API", issue="...")]
impl<T: fmt::Debug + ?Sized> ToDebug for T {
    default fn to_debug(&self) -> String {
        use fmt::Write;
        let mut buf = String::new();
        buf.write_fmt(format_args!("{:?}", self))
           .expect("a Debug implementation returned an error unexpectedly");

Can't we just add a method on Debug to do this conversion? I'm pretty sure ToString was a mistake, and I don't see the reason to add yet another trait for this. Ideally, to_string would be on Display, but it's too late for that (because there is likely some code that relies on ToString, directly). Also, making a new trait would create some confusion, should I implement ToDebug directly, or implement Debug. The correct answer is always Debug because it is far more applicable.


No objection here. I don't have the history of ToString. If we can add a method to Debug instead with a default implementation, that seems perfect.

Note that neither Debug nor Display are in the prelude. I believe that this is because their fmt methods conflict. If .to_debug() is on Debug, it will require importing std::fmt::Debug to use the method.

Interestingly, if fn to_string(&self) -> String had been a method on Display rather than its own trait, we wouldn't have needed specialization to specialize str/String/Cow<str> ::to_string.

I assume that to_debug isn't going to be used that much, so this shouldn't be a problem

Debug is in core and String is in alloc so none of the methods can mention String. So it will have to be done the same way as ToString.


Oh, interesting.

I imagine that could work differently in a future modular std, but in the meantime, sounds like we do need a ToDebug to make this work.

Off topic for this thread, but I just want to jump to the defense of ToString. It's really great as a teaching tool when explaining traits:

  • It has exactly one method with a straightforward and obvious signature, making the behavior very easy to explain.
  • It implements an interface which is very common in other languages, so users are familiar with the idea.
  • It's in the prelude, so you don't need to worry about imports being wrong.
  • It's object safe, so you can use it to teach about trait objects.
  • It has a blanket impl, so you can use it to teach about blanket impls.

I love ToString for these reasons alone, and its also my go-to whenever I need to create a trait object in a playpen to test something.


x.to_debug() is just minimally more convenient than format!("{:?}", x). Debug also supports formatting, e.g. pretty-printing mode, so you'd need a method or an arg for format!("{:#?}", x).

I don't think it's worth making the change, especially that Debug output as a string is mainly used for ugly hacks like parsing the debug output to get private details of a type.


"mainly"? I'm sure that people do that, but that seems unlikely to be the primary use case for rendering Debug output.

One of my use cases for this: error types whose Debug output provides a full backtrace.

1 Like

"mainly" is subjective of course. It's my impression from questions on forums and mentions elsewhere on the net that I've seen.

Note that you described a case for generating a nice Debug format, and printing it. That doesn't necessarily require capturing of the Debug output as a String, and especially not to a degree that would require a convenience function for it.

1 Like