# Making format machinery more amenable to dynamic formatting

**URL:** <https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089>\
**Category:** Uncategorized\
**Created:** [October 12, 2019, 6:26am UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089 "2019-10-12T06:26:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![birkenfeld](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/birkenfeld/32/1150_2.png) [@birkenfeld](https://internals.rust-lang.org/u/birkenfeld)\
**Post date:** [October 12, 2019, 6:26am UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/1 "2019-10-12T06:26:22Z")

</div>

For a project I have to implement some formatting of values with a user-provided format string. Unfortunately, all crates that allow this are either nightly-only (`rt_format`) or incomplete.

I'm fine with parsing the format string myself (although Rust could expose its own routine to do it in the library), but there is no stable way to pass formatter parameters, like align/width/precision, dynamically. And I really don't want to reimplement number formatting for all the different types.

I see two ways out of this:

- Large impact: make the whole `V1` machinery public and stable. Its naming is versioned after all, so I don't see the reason to keep it unstable; a new version would probably introduce new `V2` APIs? (Also, has the V1 API changed incompatibly at all since Rust 1?)

- Less impact: make the formatting settings of the `Formatter` read-write accessible. For example, [`fill()`](https://doc.rust-lang.org/std/fmt/struct.Formatter.html#method.fill) could get a setter `set_fill()` and so on. I'm not aware of a downsides here, and the new API surface is pretty minimal and does not expose any of the `V1` machinery. It does mean that Debug/Display/... impls can change user intention given by the format string, but they're already free to ignore it completely and just write whatever to the formatter.

- Alternative, also less impact: allow stable creation of an [`Arguments`](https://doc.rust-lang.org/std/fmt/struct.Arguments.html) instance with flags selected at runtime, for the very restricted case of only one value to format. This can then be passed to [`write_fmt`](https://doc.rust-lang.org/std/fmt/struct.Formatter.html#method.write_fmt), again without exposing any `V1` details.

What do you think? Does this need an RFC? I'm obviously willing to work on any chosen solution.

---

<div class="post-metadata">

**Author:** ![djc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/djc/32/1592_2.png) [@djc](https://internals.rust-lang.org/u/djc)\
**Post date:** [October 12, 2019, 8:34am UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/2 "2019-10-12T08:34:00Z")

</div>

Another alternative (which is probably unattractive for you and your immediate problem, but nonetheless): spend some designing a comprehensive V2 to replace V1, which is amenable for making public & stabilization.

FWIW, I've wanted to use the formatting internals a bunch of times, so it would be nice to (finally) make some steps towards that. Personally I don't have any short-term concerns, so figuring out the right APIs for the long-term would have my preference (and not cluttering the API with a V1 seems preferable in the absence of backwards compatibility concerns).

---

<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:** [October 12, 2019, 10:25am UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/3 "2019-10-12T10:25:46Z")

</div>

> [@birkenfeld](#):
>
> there is no stable way to pass formatter parameters, like align/width/precision, dynamically

There is: you can pass both width and precision as named or positional parameters with the `$` syntax.

You can't pass alignment or sign dynamically, but they have few enough choices that you could map all the combinations to different format calls, or in the case of alignment, format as a string first then format that string with an alignment.

(That said, we ought to have a syntax to dynamically pass alignment and sign parameters.)

---

<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:** [October 12, 2019, 11:21am UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/4 "2019-10-12T11:21:07Z")

</div>

> [@josh](#):
>
> There is: you can pass both width and precision as named or positional parameters with the `$` syntax.

I struggle with that syntax every single time, FWIW.^^ Too many sigils. Also, postfix-`$` is really weird syntax.

Here's how it looks (took me like 5min to get valid syntax):

```rust
fn main() {
    let width = 22;
    let n = 1024;
    println!("{:>width$}", n, width=width);
}

```

EDIT: Ah, there's [an example in the docs](https://doc.rust-lang.org/nightly/std/fmt/index.html#width) that I missed so far because it is _below_ the grammar... (There were examples above so when the grammar came I assumed that means examples are done.)

I [opened a PR](https://github.com/rust-lang/rust/pull/65332) to reorder the docs to make them more readable.

---

<div class="post-metadata">

**Author:** ![birkenfeld](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/birkenfeld/32/1150_2.png) [@birkenfeld](https://internals.rust-lang.org/u/birkenfeld)\
**Post date:** [October 12, 2019, 12:55pm UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/5 "2019-10-12T12:55:57Z")

</div>

> [@josh](#):
>
> There is: you can pass both width and precision as named or positional parameters with the `$` syntax.

I know, and that's going to be my workaround for now (even if something is done here, it'll take a while until stabilization). But I'm limiting myself to two settings (sign and zero-padding) since combinatorial explosion is at hand...

> [@josh](#):
>
> (That said, we ought to have a syntax to dynamically pass alignment and sign parameters.)

And alternate flag, and zero-padding, and fill character. The last is especially tricky since it can be any character, even `}`! (TIL.)

Don't get me wrong, I'd be happy if it was possible in that way, but it's going to be a nightmare to find a syntax that is both compatible and at least not less obvious than the existing `$` and `*` sigils.

But it would be much easier (to define _and_ use) to construct a struct equivalent of the format string in normal Rust, which is what an `Arguments` method as in my third suggestion would do.

---

<div class="post-metadata">

**Author:** ![birkenfeld](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/birkenfeld/32/1150_2.png) [@birkenfeld](https://internals.rust-lang.org/u/birkenfeld)\
**Post date:** [October 12, 2019, 1:02pm UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/6 "2019-10-12T13:02:19Z")

</div>

> [@djc](#):
>
> Another alternative (which is probably unattractive for you and your immediate problem, but nonetheless): spend some designing a comprehensive V2 to replace V1, which is amenable for making public & stabilization.

There was a thread a while ago awhile ago about speeding up formatting with a new behind-the-scenes implementation:

> [@Changing core::fmt for speed](https://internals.rust-lang.org/t/changing-core-fmt-for-speed/5154):
>
> The current machinery in core::fmt is built in a way that any expansion of format!/write!/etc keeps most of the code out of the call site, and inside core::fmt::write(). To do this, it has to pass an array of arguments, and since the arguments may be different types, it uses (sort-of-but-different) trait objects to do so. This results in formatting to be noticeably slower than pushing values to a string manually. After some rusty archaeology, the best I could find was [this issue](https://github.com/rust-lang/rust/issues/3571), stating: It …

---

<div class="post-metadata">

**Author:** ![tspiteri](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tspiteri/32/7283_2.png) [@tspiteri](https://internals.rust-lang.org/u/tspiteri)\
**Post date:** [October 12, 2019, 5:51pm UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/7 "2019-10-12T17:51:58Z")

</div>

Though maybe not so ergonomic, when I have some complex formatting I end up writing something like

```rust
fn display_options(val: &Val, options: Options) -> impl Display + '_ {
    // ...
}
println!("{}", display_options(&val, options));

```

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [January 10, 2020, 5:52pm UTC](https://internals.rust-lang.org/t/making-format-machinery-more-amenable-to-dynamic-formatting/11089/8 "2020-01-10T17:52:00Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
