# Mut String += format\_args!(…);

**URL:** <https://internals.rust-lang.org/t/mut-string-format-args/19461>\
**Category:** language design\
**Created:** [September 1, 2023, 9:23am UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461 "2023-09-01T09:23:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dwarsloeper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dwarsloeper/32/11073_2.png) [@Dwarsloeper](https://internals.rust-lang.org/u/Dwarsloeper)\
**Post date:** [September 1, 2023, 9:23am UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/1 "2023-09-01T09:23:27Z")

</div>

I have various macros that boil down to `format_args!()`. They go into one another. Sometimes I also want to append them to an existing `String`. If I used `format!()` or `.to_string()`, it would work, at the price of an unwanted heap allocation.

Instead, what I'd like is the following. Of course, owning neither `AddAssign` nor `String` I can't currently do this myself. (For now I have an ugly workaround by wrapping the String.) I think this would make sence as part of `std`. Not sure about the `Err`. I hope this concrete usage couldn't cause more trouble than the existing `+= str`.

```rust
impl std::ops::AddAssign<std::fmt::Arguments<'_>> for String {
    fn add_assign(&mut self, other: std::fmt::Arguments<'_>) {
        std::fmt::write(self, other).unwrap();
    }
}

```

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 1, 2023, 9:42am UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/2 "2023-09-01T09:42:59Z")

</div>

> [@Dwarsloeper](#):
>
> I have various macros that boil down to `format_args!()`. They go into one another. Sometimes I also want to append them to an existing `String`. If I used `format!()` or `.to_string()`, it would work, at the price of an unwanted heap allocation.

I'm having a hard time imagining your exact use-case from this vagus description alone. Would you mind elaborating a bit what "boil down to `format_args!()`" means, and how you use your macros so that you "sometimes append to a `String`" (and presumably sometimes do something else)? Like, some code example of what the call to the macro would like and how it's improved with such a `+=` implementation. Maybe, also the question "why isn't `fmt::write` and/or `write!` sufficient" should be answered.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [September 1, 2023, 1:50pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/3 "2023-09-01T13:50:08Z")

</div>

The problem is that the efficient way is more verbose than less performant ways of appending formatted string:

```rust
use std::fmt::Write;
let _ = write!(&mut s, "{x}");

```

vs

```rust
s += &format!("{x}");

```

or

```rust
s.push_str(&format!("{x}"));

```

While I usually don't like the `+` overload on strings, I think support for `format_args!` here is a very clever trick, and gives `String` a pretty compact and relatively efficient formatted append.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [September 1, 2023, 2:00pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/4 "2023-09-01T14:00:42Z")

</div>

One thing that could help this is if there were an inherent `write_fmt(…) -> ()` on `String`, then you wouldn’t need to `use` the trait or discard the return value.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [September 1, 2023, 2:06pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/5 "2023-09-01T14:06:19Z")

</div>

That would be very nice, but it would break existing code that calls `write!(string, "...").unwrap()`.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [September 1, 2023, 2:39pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/6 "2023-09-01T14:39:53Z")

</div>

Mmmm, unless it was done as an edition hack like array intoiterator, and that doesn’t feel worthwhile to me.

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [September 1, 2023, 3:19pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/7 "2023-09-01T15:19:46Z")

</div>

Relevant ACP to make `write!(str, ...)` a little easier.

> <https://github.com/rust-lang/libs-team/issues/261>
>
> \# Proposal
> 
> \## Problem statement
> 
> It would be great if this code compiled:
> …\`\`\`rust
> fn main() {
> let mut s = String::new();
> write!(s, "hello").unwrap();
> }
> \`\`\`
> Using \`write!\` to append to a \`String\` is one of these neat Rust things that are not obvious to discover, but once you know about it it is amazingly useful.
> 
> \## Solution sketch
> 
> The code currently fails saying that \`io::Write\` or \`fmt::Write\` needs to be imported or a \`write\_fmt\` method needs to be added. (The right trait to import is \`fmt::Write\`, as I found out by trial-and-error.)
> 
> From the error message it sounds like that could be avoided if we simply added a \`write\_fmt\` inherent method to \`String\`. That would just get one minor roadblock out of the way which sounds like a win to me. :)
> 
> \## Alternatives
> 
> We could decide the roadblock isn't bad enough to warrant doing anything.
> 
> \## What happens now?
> 
> This issue is part of the libs-api team \[API change proposal process\]. Once this issue is filed the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
> 
> \[API change proposal process\]: https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html
> 
> \## Possible responses
> 
> The libs team may respond in various different ways. First, the team will consider the \*problem\* (this doesn't require any concrete solution or alternatives to have been proposed):
> 
> \- We think this problem seems worth solving, and the standard library might be the right place to solve it.
> \- We think that this probably doesn't belong in the standard library.
> 
> Second, if there's a concrete solution:
> 
> \- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
> \- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

And as pointed out there, [rust-analyzer has this macro](https://github.com/rust-lang/rust-analyzer/blob/62268e474e9165de0cdb08d3794eec4b6ef1c6cd/crates/stdx/src/macros.rs#L13-L20):

```rust
 /// Appends formatted string to a `String`. 
 #[macro_export] 
 macro_rules! format_to { 
     ($buf:expr) => (); 
     ($buf:expr, $lit:literal $($arg:tt)*) => { 
         { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); } 
     }; 
 }

```

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [September 1, 2023, 3:30pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/8 "2023-09-01T15:30:21Z")

</div>

At that point, why bother with `write!` instead of `<_ as ::std::fmt::Write>::write_fmt(...)`?

---

<div class="post-metadata">

**Author:** ![Dwarsloeper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dwarsloeper/32/11073_2.png) [@Dwarsloeper](https://internals.rust-lang.org/u/Dwarsloeper)\
**Post date:** [September 1, 2023, 3:33pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/9 "2023-09-01T15:33:27Z")

</div>

By boil down I mean, they are construction helpers for things like urls and html constructs and tags. Each ultimately returns a `format_args!()`.

Instead of needing to explicitly do `fmt::write` stuff, I'm looking for nice syntax:

```rust
let mut s = "prefix".to_string();
s += html_popup!(… tag!(… url!(…) …) …);
// which macro-expands to
s += format_args!(…);

```

This seems sensible as `format_args!()` is semantically stringish.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 1, 2023, 3:54pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/10 "2023-09-01T15:54:53Z")

</div>

Thanks for the clarification. That's what I think I'd have guessed, too, but I like the more explicit code example to be sure there's no misinterpretation 😇

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [September 1, 2023, 4:36pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/11 "2023-09-01T16:36:21Z")

</div>

`write!` contains the `format_args!` within itself, the two options would be like

```rust
write!(&mut s, "Hello {name}!");
s.write_fmt(format_args!("Hello {name}!"));

```

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [September 1, 2023, 4:40pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/12 "2023-09-01T16:40:18Z")

</div>

Eh, ok. The embedded `use` annoys me, but I suppose it's scoped. They may also want the auto-ref method resolution of `.write_fmt` vs. `::write_fmt`.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [September 1, 2023, 5:02pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/13 "2023-09-01T17:02:01Z")

</div>

Would it be possible to have an attribute to suppress the `#[must_use]` of a type when defining a function with said function as return type? Then `String::write_fmt` could use this attribute to indicate that it never returns an error.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [September 1, 2023, 5:17pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/14 "2023-09-01T17:17:18Z")

</div>

> [@bjorn3](#):
>
> Then `String::write_fmt` could use this attribute to indicate that it never returns an error.

Speaking of which, it would be nice to have a try-variant that did report errors on failed allocations etc.

---

<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:** [September 1, 2023, 5:34pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/15 "2023-09-01T17:34:33Z")

</div>

Given pattern types, we could specify that a function never returns Err.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 1, 2023, 5:48pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/16 "2023-09-01T17:48:52Z")

</div>

Is there perhaps desire for a (name to be determined, …, let’s call it `push_display` for now) method on `String` with a

```rust
fn push_display(&mut self, x: impl fmt::Display) -> ()

```

or alternatively

```rust
fn push_display(&mut self, x: &impl fmt::Display) -> ()

```

signature? I.e. supporting not only `fmt::Arguments<'_>` but simply any `Display` type.

* * *

Probably implemented along the lines of

```rust
{
    x.fmt(&mut Formatter::new(self)).unwrap()
}

```

which should be equivalent (but slightly cheaper) compared to

```rust
{
    self.write_fmt(format_args!("{x}")).unwrap()
}

```

(it’s a bit like a slight generalization\[1\] of the [`ToString` (default) implementation](https://doc.rust-lang.org/1.72.0/src/alloc/string.rs.html#2520-2527); also peeking there, looks like the `.unwrap()` should instead be “`.expect("a Display implementation returned an error unexpectedly")`”; and we might also want to mirror, or perhaps even somehow combine, the specialization of `ToString` to get the same performance; e.g. for `&str` it should simply call `push_str`.)

* * *

1. as in: it doesn’t also create the `String`

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [September 2, 2023, 10:23am UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/17 "2023-09-02T10:23:47Z")

</div>

I do like `s += format_args!("...");`, that seems indeed more discoverable than `write!(s, "...").unwrap()`. So it seems better to me than what my ACP proposes.

`s.push_display(format_args!("...))"` also works I guess but that's more nested so a bit harder to type and read.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [September 3, 2023, 2:12pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/18 "2023-09-03T14:12:03Z")

</div>

One issue with `+=` supporting `fmt::Arguments<'_>` is that it would break code like

```rust
fn main() {
    let mut s = String::from("Hello");
    let additional = String::from(" World!");
    s += &additional;
}

```

* * *

As a demo see how the use-case for [this re-implementation](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1805896ef645651bd6b065814abad066) of the relevent API [breaks](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4d813bc9ce29ddedab017d3dd0184251) by the additional impl.

```plaintext
error[E0277]: cannot add-assign `&String` to `String`
  --> src/main.rs:27:7
   |
27 | s += &additional;
   | ^^ no implementation for `String += &String`
   |
   = help: the trait `AddAssign<&String>` is not implemented for `String`
   = help: the following other types implement trait `AddAssign<Rhs>`:
             <String as AddAssign<Arguments<'_>>>
             <String as AddAssign<&str>>

```

* * *

Maybe, common use-cases can be saved by _also_ adding extra implementations for RHS types such as `&String`, but there’d always be at least _some_ degree of breakage left.

Although now, on second thought, I’m kind-of wondering, are there any common crates that come with a `AddAssign<CustomType> for String` implementation, and if so would helping users of such crates motivate additional implementations for things like `&String` anyways.

On third thought… @Dwarsloeper instead of wrapping the string, you can also wrap the `format_args` into [a new type that implements both `Display` and `AddAssign<Self> for String`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2ba8aeb3b1fcc5083fca820dda952c9d); maybe that’s the nicer quick workaround?

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [September 3, 2023, 2:37pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/19 "2023-09-03T14:37:45Z")

</div>

Yet another case where [deref coercion during trait resolution](https://internals.rust-lang.org/t/pre-rfc-enable-deref-coercion-on-trait-bound-parameters/18375) would help. Side-note: I haven't tried making that into a full-blown RFC yet because it needs to support more than just deref coercion for things like arrays.

---

<div class="post-metadata">

**Author:** ![drewkett](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/drewkett/32/7095_2.png) [@drewkett](https://internals.rust-lang.org/u/drewkett)\
**Post date:** [September 3, 2023, 5:41pm UTC](https://internals.rust-lang.org/t/mut-string-format-args/19461/20 "2023-09-03T17:41:52Z")

</div>

Another less ideal aspect to `+=` is that it raises the question of whether we should support `+`. If it’s not supported, it makes the String API a bit weird. But if we do support it, what types should/could work with `Add`?

[Next page](https://internals.rust-lang.org/t/mut-string-format-args/19461.md?page=2)
