# Add an easier way to append \`T: Display\` to \`String\` to stdlib?

**URL:** <https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607>\
**Category:** libs\
**Created:** [July 20, 2019, 1:25pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607 "2019-07-20T13:25:45Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 20, 2019, 1:25pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/1 "2019-07-20T13:25:45Z")

</div>

I am regularly annoyed when I need to append new formatted content to an existing `buf: &mut String`.

I _think_ the official way to do this is

```rust
use std::fmt::Write;

write!(buf, "{}", data).unwrap();

```

The problem with this is:

- You need to import `Write`
- It's hard to remember _which_ `Write` should be imported
- there's `unwrap` that can't actually fire

For this reason, I often just do `buf += &format!("...")` or `buf += &data.to_string()`, which is nicer to write, but is horrible semantics-wise.

Do other folks percieve this as a problem that needs to be solved? My proposal would be to add a second form to the `format` macro, so that the original example could be written as

```rust
format!(buf, "{}", data)

```

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 20, 2019, 3:46pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/2 "2019-07-20T15:46:23Z")

</div>

There's a couple of obnoxious questions, I think, mostly of the form "are _just_ strings allowed in the new `format!()` overload"? `Vec<u8>` is, technically, a reasonable choice here. I suspect that in this case we wind up with a variant of `Write` that does not return errors.

---

<div class="post-metadata">

**Author:** ![burntsushi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/burntsushi/32/279_2.png) [@burntsushi](https://internals.rust-lang.org/u/burntsushi)\
**Post date:** [July 20, 2019, 4:02pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/3 "2019-07-20T16:02:10Z")

</div>

I share your annoyance to some degree. Your `format!` idea is a nice hack, but it feels mildly uncomfortable. Namely, the addition of `buf` turns something that once _returned_ a `String` to something that returns nothing, but modifies an argument in place. It feels a little jarring to me at first blush, and I don't know whether that would subside after more use of it. (I can't think of any widely used macro with similarish behavior.)

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 20, 2019, 4:13pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/4 "2019-07-20T16:13:01Z")

</div>

Yeah, it's definitely true that such macro overloading is unusual. An obvious boring alternative is to add a new macro, like `format_to!(buf, "{fmt}", args...)`. One more option is to use `log`'s syntax: `format!(to: buf, "{fmt}", args)`.

I think I _mildly_ prefer the overloading version though: it's unusal for Rust, but the general idea of "operation allocates by default, but can use a provided buffer" seems sound. For example, Kotlin's alternative to `.collect` works this way: [https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html).

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 20, 2019, 4:49pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/5 "2019-07-20T16:49:31Z")

</div>

Inb4 "this should be a crate": this is [a crate](https://crates.io/crates/format-buf) 🙂

However I feel that such small convenience utilities belong to std.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 20, 2019, 6:20pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/6 "2019-07-20T18:20:04Z")

</div>

> [@matklad](#):
>
> It's hard to remember _which_ `Write` should be imported

I don't share this sentiment; there are only ever two `Write`s you need to chose from, and you know it's `fmt::Write` because you want to write to a `String`, which, being guaranteed UTF-8, can't accept arbitrary bytes like the bytestream-oriented `io::Write`.

However, we could add `fmt::Write` to the prelude instead, as wanting to append to a buffer in-place is fairly common. A separate `append_format!` macro would also be nice to hide the spurious `unwrap`. I'm most definitely _against_ "overloading" the already-existing `format!` macro though, for the reasons listed above _plus_ the fact that it's wildly inconsistent with every other formatting purpose having its very own macro (think `format!`, `write!`, `format_args!`, even `println!` vs. `eprintln!`).

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 20, 2019, 7:43pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/7 "2019-07-20T19:43:44Z")

</div>

> [@H2CO3](#):
>
> it's wildly inconsistent with every other formatting purpose having its very own macro

Hm, `eprintln!` example makes me think, that, _if_ we go with a separate macro, `sprint / sprintln` might be a good choice, as it resembles `printf / sprintf`.

> However, we could add `fmt::Write` to the prelude instead

I think this wouldn't be backwards compatible in practice: both `io::Write` and `fmt::Write` have the same signature for `write_fmt` (precisely to make `write!`s duck typing work), so having both in scope could lead to method selection ambiguity errors.

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 20, 2019, 7:45pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/8 "2019-07-20T19:45:34Z")

</div>

What we could do though, is to add `write_fmt` inherent method for `String`. We'll have to use the `-> Result` signature though to be backwards compatible, so that won't rid us from `.unwrap()`.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 21, 2019, 1:06am UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/9 "2019-07-21T01:06:32Z")

</div>

> [@matklad](#):
>
> sprint / sprintln

Except that's what C and Go call `format!()`... =(

> [@matklad](#):
>
> so that won't rid us from `.unwrap()` .

Something something `Result<T, !>` something something hack `#[must_use]` to not fire on `Result<T, !>`?

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 21, 2019, 5:16am UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/10 "2019-07-21T05:16:51Z")

</div>

> [@mcy](#):
>
> Something something `Result<T, !>` something

`.unwrap()` could just be part of the macro (or a lower-level formatting function it calls), as it is in the case of other infallible formatting macros like `format!()` itself, which generates calls to `alloc::fmt::format`, which in turn [`expect()`s the returned `Result`](https://doc.rust-lang.org/src/alloc/fmt.rs.html#566).

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [July 21, 2019, 2:45pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/11 "2019-07-21T14:45:08Z")

</div>

I find this tangentially related to [https://users.rust-lang.org/t/crates-that-use-the-inherent-trait-method-pattern/30381](https://users.rust-lang.org/t/crates-that-use-the-inherent-trait-method-pattern/30381) ; what about

```rust
impl String {
   #[inline]
   fn push_fmt (self: &'_ mut Self, args: fmt::Arguments)
   {
       fmt::Write::write_fmt(self, args)
           .expect("a formatting trait implementation returned an error");
   }
}

```

```rust
buf.push_fmt(format_args!("{}", data));

```

?

* * *

Otherwise the `format_to!` option is not too bad: with a hack it could use the kind of string literal to choose which `Write` to use:

- a string literal to use `fmt::Write`;

- a bytestring literal for `io::Write`.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 22, 2019, 5:50pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/12 "2019-07-22T17:50:04Z")

</div>

> [@H2CO3](#):
>
> `.unwrap()` could just be part of the macro (or a lower-level formatting function it calls), as it is in the case of other infallible formatting macros like `format!()` itself, which generates calls to `alloc::fmt::format` , which in turn [`expect()` s the returned `Result`](https://doc.rust-lang.org/src/alloc/fmt.rs.html#566).

I'm not sure I'm too happy about that? I would hope that `write!(w, ..)` would return any IO errors, rather than crashing.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [July 22, 2019, 7:17pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/13 "2019-07-22T19:17:01Z")

</div>

That's not at all what I'd expect `format!(buf, ...)` to mean; I'd expect that to _replace_ the contents of `buf`, not append to them.

I do absolutely agree that having to import `Write` feels onerous. If we had only one `Write` rather than two, I'd expect `fmt::Write` to appear in the prelude. We have two `Write` traits, however.

In the standard library itself, we don't have any overlapping implementations of the two `Write` traits. In theory, someone could implement both traits on one type, in which case importing either trait in the prelude _could_ break compatibility. In practice, I wonder if anything would actually break if the prelude imported both `Write` traits.

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 22, 2019, 7:44pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/14 "2019-07-22T19:44:22Z")

</div>

> [@josh](#):
>
> I'd expect that to _replace_ the contents of `buf` , not append to them.

That’s an interesting observation! I see how replace could be an expected behavior here. I have a strong expectation for append because it matches the standard rust pattern: [BufRead in std::io - Rust](https://doc.rust-lang.org/std/io/trait.BufRead.html#method.read_line) . But that is because I misuse read\_line every single time 😃

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [July 22, 2019, 7:50pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/15 "2019-07-22T19:50:58Z")

</div>

> [@josh](#):
>
> I do absolutely agree that having to import `Write` feels onerous. If we had only one `Write` rather than two, I'd expect `fmt::Write` to appear in the prelude. We have two `Write` traits, however.

I’d like to reiterate that if we want to solve the import problem, it would be sufficient to add write\_fmt inherent method for string. This is exactly how fmt::Formatter works: the method is inherent, macro uses “duck typing”, so no import is required.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 22, 2019, 11:16pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/16 "2019-07-22T23:16:32Z")

</div>

> [@josh](#):
>
> That's not at all what I'd expect `format!(buf, ...)` to mean; I'd expect that to _replace_ the contents of `buf` , not append to them.

I think that's only an expectation if you're using `sprintf()`, I think? In C++ I'm used to using Abseil for string handling, where everything matches the Rust convention (`std::string*`s are appended to). Case in point, [`absl::StrAppendFormat`](https://github.com/abseil/abseil-cpp/blob/master/absl/strings/str_format.h#L330) is _exactly_ like `write!`.

(I mean yes it says `Append` in the name but appending is 99% of the times what I want and `std::string::clear` exists, exactly like in Rust.)

---

<div class="post-metadata">

**Author:** ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)\
**Post date:** [July 25, 2019, 9:55pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/17 "2019-07-25T21:55:38Z")

</div>

A provided method on ToString seems like a potential solution.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 26, 2019, 6:50am UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/18 "2019-07-26T06:50:33Z")

</div>

Formatting into an in-memory string buffer is not supposed to ever return an `Err`, though. That's why `format!()` and the `ToString` blanket impl for `Display` can directly return a `String`, instead of a `fmt::Result<String>`, according to what is [explicitly stated in the official documentation](https://doc.rust-lang.org/std/string/trait.ToString.html#panics).

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [July 26, 2019, 5:21pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/19 "2019-07-26T17:21:43Z")

</div>

It's interesting to me that a Display implementation returning Err is defined as an "incorrect Display implementation". Why is Display not allowed to fail?

Does the same principle apply to the Formatter trait and any custom implementations of that?

If that's something we want to guarantee, is there some way we could update the types or guarantees involved (perhaps involving the introduction/deprecation of functions) to guarantee that? For instance, could we introduce a new infallible method to Display, with a default implementation that calls `fmt` and `.expect`?

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [July 26, 2019, 8:36pm UTC](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607/20 "2019-07-26T20:36:07Z")

</div>

> [@josh](#):
>
> Why is Display not allowed to fail?

If I interpret [this earlier explanation](https://internals.rust-lang.org/t/format-to-string-does-not-panic-on-std-fmt-error-intentional-or-not/) correctly, it's that formatting is by itself considered an infallible operation (and thus `Display` impls aren't supposed to produce errors on their own), but there is one reason it might fail: if an error is generated in the underlying writer itself, which only needs to be able to be _propagated,_ hence the `Result` return type. However, writing to a memory buffer is expected never to fail.

[Next page](https://internals.rust-lang.org/t/add-an-easier-way-to-append-t-display-to-string-to-stdlib/10607.md?page=2)
