Repr formatter with ShowRepr trait


#1

Hi,

somethimes I wish Rust had repr formatter, similar to Python repr function.

println!("{:?}", "\n");

should print

"\n"

instead of newline.

Repr can be used, for instance, in assert_eq! macro instead of {}, which prints something inappropriate in cases like this:

assert_eq!("\n", "\r");

ShowRepr trait is used instead of Show for {:?} formatter.

IMO, Show for Option or Vec should use Repr to for its content, like this:

impl<T : ShowRepr> Show for Option<T> {
    fn fmt(...) {
        match self {
            // ShowRepr is used instead of Show
            Some(v) => format!("Some({:?})", v),
            None => format!("None"),
        }
    }
}

So

println!("{}", Some("None"));

prints

Some("None")

instead of

Some(None)

but I’m not sure.


#2

I’m quite interested in this as well. I have half an RFC written up, I’m just trying to figure out how the default case should be. I assume anything Show should automatically be able to be Repr. However, we can’t do impl<T: Show> Repr for T, because then nothing can have specialized Repr vs Show.

The one solution I think works well is to, instead of adding a new trait, add a new method to Show, that has a default implementation. This way, all Show can be repred, and anything that wants to specialize can override the default method.

It’d look something like this:

trait Show for Sized? {
    fn fmt(&self, &mut fmt::Formatter) -> fmt::Result;

    fn repr(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.fmt(f)
    }
}

And an example implementation:

impl Show for MaybeOwned {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }

    fn repr(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Slice(s) => write!(f, "Slice({:?})", s),
            Owned(s) => write!(f, "Owned({:?})", s),
        }
    }
}

Ideally, str would use write!(f, "\"{}\"", self), leave us with Slice("Foo").


#3

I’d say that ideally it would use proper quoting.


#4

It would be nice if this would be using a more intelligent formatter that can indent and wrap. Something like ruby’s pprint system or Python’s pretty library.


#5

Hi Armin,

The python repr that is (almost) always is single line is nice. This means that it’s safe to put in logs or print to console, even if value is something that is got from third party.

For example if you are printing error value:

print("Server returned bad response: ", repr(e))

It’s guaranteed that it will never print:

Server returned bad response:

[ ... 1000 newlines ... ] 

Something wrong happened, but it can be fixed if you run:
sudo rm -rf /

#6

I’m not saying it should be indented by default. The fact that the repr system in Python does not support optional indentation has been a major problem for a long time now and it’s impossible to fix now. But a new language should not make the same mistake.


#7

+100

I hope to print an arbitrary [u8] “as closely to str as possible” with your proposed (customizable?) “repr” format.

I frequently parse (often partily binary) message protocols in C++ and I rely on something like this for debugging / error report:

static string sanitize(const char *p, size_t len) {
    ostringstream oss;
    for (size_t i = 0; i < len; ++i) {
        if (isgraph(p[i]))
            oss << p[i];
        else
            oss << '[' << setw(2) << setfill('0') << std::hex << (unsigned)(unsigned char)p[i] << std::dec << setfill(' ') << ']' ;
    }
    return oss.str();
}

(from_utf8_lossy() is “too lossy” to use with binary protocols.)


#8

There is also a thread related to this topic: http://discuss.rust-lang.org/t/show-to-string-and-guidelines/590