rust-lang / libs-team

The home of the library team
Apache License 2.0
127 stars 19 forks source link

Arbitrary alternate flags in `std::fmt::Formatter` #155

Open yuhr opened 1 year ago

yuhr commented 1 year ago

Proposal

(Originally I've posted this to https://github.com/rust-lang/rfcs/issues/3359 but I've noticed this place is more reachable by the libs team)

Problem statement

Currently, std::fmt::Formatter::alternate feature is meant to support just a single bool value, being written like "{:#}" in format templates, but what if one wants to support multiple flags?

There seemed to be a dedicated API for it: std::fmt::Formatter::flags, but this was marked as deprecated and even the return type is a magic number u32. A possible workaround is to abuse std::fmt::Formatter::fill API to indicate a flag by a single char, but this is still magical and there's no natural way to specify multiple flags at a time.

Therefore, at this time, the only correct way to solve this is to provide a dedicated method like MyType::to_string_with_flags on the formatted type, that may cause unnecessary cognitive loads to their users.

Motivation, use-cases

I wonder if the syntax "{:#}" was more extensive like "{:#flags}". This way, users can fully utilize the well-known macro format! instead of calling a dedicated method.

I think the format of the flag string should be completely left to users because use cases definitely vary, such as:

Solution sketches

Ideally, the signature of std::fmt::Formatter::alternate should be changed to:

pub fn alternate(&self) -> Option<&str>

But obviously this is a breaking change, so I'd propose a new method to be added:

pub fn alternate_flags(&self) -> Option<&str>

where the resulting &str is the string after the #. Of course it can be empty, i.e. "{:#}" => Some(""), so that the alternate method can be implemented by just self.alternate_flags().is_some().

Links and related work

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 in its weekly meeting. You should receive feedback within a week or two.

m-ou-se commented 8 months ago

I don't think we should be adding more flags (let alone what is effectively infinite number of flags ^^'). I think wrapper structs are preferrable over more flags. Basically:

println!("{}", IsoDisplay(time)); // This,
println!("{}", time.display_iso()); // or this,
println!("{:#iso}", time); // but not this.

For various reasons: