-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
format! should support multiple formats for one argument #9456
Comments
Hmm, I agree with you. When I originally wrote this I wasn't intending on having I suppose it would be kinda nice to be able to use the same argument with different formatting constraints, and there's not really a reason that it's not done except for the fact that it's not implemented. It'll involve a little bit of trickery, but none of the arguments are moved anyway so there's no worries there. |
I'm going to remove this coercion for now, but I like the idea of using multiple formats, so I'm renaming the title of this issue to be more appropriate for the desired feature. Previous title was: "Formatting for named arguments persists to later mentions, leading to confusion" |
As mentioned in rust-lang#9456, the format! syntax extension would previously consider an empty format as a 'Unknown' format which could then also get coerced into a different style of format on another argument. This is unusual behavior because `{}` is a very common format and if you have `{0} {0:?}` you wouldn't expect them both to be coereced to the `Poly` formatter. This commit removes this coercion, but still retains the requirement that each argument has exactly one format specified for it (an empty format now counts as well). Perhaps at a later date we can add support for multiple formats of one argument, but this puts us in at least a backwards-compatible situation if we decide to do that.
As mentioned in #9456, the format! syntax extension would previously consider an empty format as a 'Unknown' format which could then also get coerced into a different style of format on another argument. This is unusual behavior because `{}` is a very common format and if you have `{0} {0:?}` you wouldn't expect them both to be coereced to the `Poly` formatter. This commit removes this coercion, but still retains the requirement that each argument has exactly one format specified for it (an empty format now counts as well). Perhaps at a later date we can add support for multiple formats of one argument, but this puts us in at least a backwards-compatible situation if we decide to do that.
Triage: all the same today. |
Rust by Examples brings me here when I was trying to impl Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RGB ({red}, {green}, {blue}) 0x{red:02X}{green:02X}{blue:02X}", red = self.red, green = self.green, blue = self.blue)
}
} |
I'd like to take this, will have the time for contributing in about a week. Fixing this would take us to almost the same level of Python in terms of ergonomics, and I see no reason to not do it! |
Just investigated this a little, seems the culprit is that I would fix this by introducing a level of indirection where every unique value-type combination appeared is evaluated only once, left-to-right to build the Any suggestions? |
Wow, I didn't know about format!("{var_name}", var_name = xxx)! Is this documented anywhere? |
I've made some progress: fn main() {
println!("{a:?} is {a}; {0:?} is {0}", "测试字符串", a="foo\u{2014}bar");
} now expands to (some irrelevant parts omitted for brevity): // prelude omitted
fn main() {
::std::io::_print(::std::fmt::Arguments::new_v1_formatted({
static __STATIC_FMTSTR:
&'static [&'static str]
=
&["",
" is ",
"; ",
" is ",
"\n"];
__STATIC_FMTSTR
},
&match (&"\u{6d4b}\u{8bd5}\u{5b57}\u{7b26}\u{4e32}",
&"foo\u{2014}bar")
{
(__arg0,
__arga) =>
[::std::fmt::ArgumentV1::new(__arg0,
::std::fmt::Debug::fmt),
::std::fmt::ArgumentV1::new(__arg0,
::std::fmt::Display::fmt),
::std::fmt::ArgumentV1::new(__arga,
::std::fmt::Debug::fmt),
::std::fmt::ArgumentV1::new(__arga,
::std::fmt::Display::fmt)],
},
{
static __STATIC_FMTARGS:
&'static [::std::fmt::rt::v1::Argument]
=
&[::std::fmt::rt::v1::Argument{position:
::std::fmt::rt::v1::Position::At(2usize),
format: (omitted),},
::std::fmt::rt::v1::Argument{position:
::std::fmt::rt::v1::Position::At(3usize),
format: (omitted),},
::std::fmt::rt::v1::Argument{position:
::std::fmt::rt::v1::Position::At(0usize),
format: (omitted),},
::std::fmt::rt::v1::Argument{position:
::std::fmt::rt::v1::Position::At(1usize),
format: (omitted),}];
__STATIC_FMTARGS
}));
} which produces the desired result
Whew... will prepare the commits and run the testsuites later. 😃 |
Actually I'm considering whether this would need an RFC, as it seems no longer possible to unambiguously reference an argument for count if multiple conflicting formats for that argument are given. Maybe we could do nothing but error on such situations. |
Ergonomic format_args! Fixes #9456 (at last). Not a ground-up rewrite of the existing machinery, but more like an added intermediary layer between macro arguments and format placeholders. This is now implementing Rust RFC 1618!
impl Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RGB ({}, {}, {}) 0x{:02X}{:02X}{:02X}", self.red, self.green, self.blue, self.red, self.green, self.blue)
}
} |
impl Display for Color {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"RGB ({0}, {1}, {2}) 0x{0:02X}{1:02X}{2:02X}",
self.red, self.green, self.blue
)
}
} |
Fix `unused_peekable` closure and `f(&mut peekable)` false positives changelog: Fix [`unused_peekable`] false positive when peeked in a closure or called as `f(&mut peekable)` The `return`/`break` changes aren't part of the fix, they allow an earlier return in some cases. `break` is replaced with `return` for style purposes as they do the same thing in this case Fixes rust-lang#9456 Fixes rust-lang#9462
Take something like the following format string:
I expect this to produce the string
"foo\u2014bar" is foo—bar
.However, what it actually produces is
"foo\u2014bar" is "foo\u2014bar"
; the behaviour of the second placeholder has changed from usingDefault
to usingPoly
.If I make the type difference explicit with the format string
"{a:?} is {a:s}"
, then I get a compilation error, which, although not what I wanted, at least tells me I can't do what I'm trying to do:My problem is with the implicit change of behaviour for named arguments from using
Default
to using what was done last. This distinctly confused me when I came across it. If using an argument with different formatting constraints is not possible (I don't see why this constraint is there, truth to tell) then I believe the unspecified format should still be interpreted asDefault
rather than what-was-done-last, and an error raised rather than this surprising behaviour.The text was updated successfully, but these errors were encountered: