<div dir="ltr">Perhaps I should elaborate on something I said in the original post. <div><br></div><div>"<span style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">There are other ways to customize the formatting behavior, but I'll keep going with some more</span><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> "</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">What I meant here is that there I currently have a two-stage lookup for a format provider.</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">1. If the type you passed in is a class, and it contains a format method with the appropriate signature, that method is invoked.</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">2. Otherwise, it looks for a specialization of llvm::format_provider<T> with a format method of the appropriate signature.</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">So in your range example, it would be perfectly reasonable to write:</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">template<typename Iter></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">class Range {</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> Iter Begin;</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> Iter End;</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> void format(raw_ostream &S, int Align, StringRef Style) {</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> }</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">};</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">template<typename T></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">Range<std::iterator_traits<T>::const_iterator> format_range(T &&t) {</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"> return </span><span style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">Range<std::iterator_traits<T>::const_iterator>(std::begin(t), std::end(t));</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">}</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">and then write:</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">std::vector<int> X = {1, 2, 3};</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">os.format("{0: }", format_range(X));</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">And just to be clear, I think that syntax has clear advantages. What I don't like is this:</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">os << "blah blah" << format<std::milli>(end-start) << "blah blah" </span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">I would much prefer to write that</span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif"><br></span></div><div><span class="inbox-inbox-Apple-converted-space" style="color:rgb(33,33,33);font-family:roboto,"helvetica neue",helvetica,arial,sans-serif">os.format("blah blah {0:ms} blah blah", end-start);<br></span></div></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Oct 12, 2016 at 9:32 PM Zachary Turner <<a href="mailto:zturner@google.com">zturner@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I think my range example was misunderstood because that isn't really what I had in mind. Apologies if that's what led to us getting off track<br class="gmail_msg"><br class="gmail_msg">However, the syntax you proposed should work just fine. Since it is extensible, you need only give the Range class in your example a format method. The only thing I would change is that I would put the separator in the string instead of the object <br class="gmail_msg"><br class="gmail_msg">print("{0:,}", Range(s.begin(), s.begin()+20))<br class="gmail_msg"><br class="gmail_msg">This way you have the freedom to display it multiple times with different presentation. Eg <br class="gmail_msg"><br class="gmail_msg">print("{0:,} {0: }")<br class="gmail_msg"><div class="gmail_quote gmail_msg"><div dir="ltr" class="gmail_msg">On Wed, Oct 12, 2016 at 9:16 PM Mehdi Amini <<a href="mailto:mehdi.amini@apple.com" class="gmail_msg" target="_blank">mehdi.amini@apple.com</a>> wrote:<br class="gmail_msg"></div><blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg">On Oct 12, 2016, at 8:33 PM, Zachary Turner <<a href="mailto:zturner@google.com" class="gmail_msg" target="_blank">zturner@google.com</a>> wrote:</div><br class="m_-3270298684112585567m_2654877915551015279Apple-interchange-newline gmail_msg"><div class="gmail_msg"><div dir="ltr" class="gmail_msg">AFAICT this appears to be the first time you've clarified that you're talking about a situation where the compile-time checking happens using something other than format strings.</div></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">I though I was clear in the thread (in the history below) when I wrote "Maybe the problem is using a string to format this in the first place” followed by this example: format(“{0}”, rPad(col_width, my_object)); where the padding is *not* in the format string.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Another example earlier in the thread was the range (let say printing elts from 10 to 20 in a vector<int>). And instead of a syntax like:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">/* Format string is {eltid, separator, <range>} */</div><div class="gmail_msg">print(“{0:,<10-20>}”, /* std::vector<int> */. v);</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">And having to actually generate the format string in the first place</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg">std::string format = format_string(“\{0:,<{0}-{1}>\}”, /* begin */ 10, /* end */ 20);</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg">I rather have something like </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">print(“{0}”, Range(“, ", v.begin()+10, v.begin()+20));</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><br class="gmail_msg"></div></div></div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><div dir="ltr" class="gmail_msg"> In Pavel's original email, he suggested compile time checking and you mentioned that I didn't object to it. But if you go back and read my response, I said we can do the compile time checking *of the format strings* using C++14. So no I didn't object to it in principle, but I never strayed from the desire to use format strings.<div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">To respond to your other point, no it doesn't make it more flexible than a non-string based solution. But does anyone want a non string-based solution? We already have one, it's called raw_ostream. And STL has another one in iostreams. sprintf and llvm::format are not more flexible than streaming operators either, and yet people still flock to them because it yields the nicest looking code. James Knight pointed out earlier that "any time someone invents a new formatting library, everyone always ends up using printf anyway". There's a reason for that, and it's because printf is string-based. That's what people want.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">So if we're talking about string-based versus non string-based, then yes, I'm married to the idea of a string based solution. </div></div></div></blockquote><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><div dir="ltr" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">That doesn't mean we can't *also* expose the underlying format functionality via an additional set of non format based functions. But string-based formatting is necessary if there is to be any adoption at all.</div></div></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">I am not convinced that just because previous attempts didn’t success, we’re stuck forever with printf. </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">At this point I’m not it is worth continuing the discussion, we can just agree to disagree on the principle.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">— </div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">Mehdi</div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"><div class="gmail_quote gmail_msg"><div dir="ltr" class="gmail_msg">On Wed, Oct 12, 2016 at 8:19 PM Mehdi Amini <<a href="mailto:mehdi.amini@apple.com" class="gmail_msg" target="_blank">mehdi.amini@apple.com</a>> wrote:<br class="gmail_msg"></div><blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg">On Oct 12, 2016, at 8:07 PM, Zachary Turner <<a href="mailto:zturner@google.com" class="gmail_msg" target="_blank">zturner@google.com</a>> wrote:</div><br class="gmail_msg m_-3270298684112585567m_2654877915551015279m_-8823961904448155070Apple-interchange-newline"><div class="gmail_msg"><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="gmail_msg"><div class="gmail_quote gmail_msg"><div dir="ltr" class="gmail_msg">On Wed, Oct 12, 2016 at 12:40 PM Mehdi Amini <<a href="mailto:mehdi.amini@apple.com" class="gmail_msg" target="_blank">mehdi.amini@apple.com</a>> wrote:<br class="gmail_msg"></div><blockquote class="gmail_quote gmail_msg" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="gmail_msg" style="word-wrap:break-word"><div class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg">On Oct 12, 2016, at 12:35 PM, Zachary Turner <<a href="mailto:zturner@google.com" class="gmail_msg" target="_blank">zturner@google.com</a>> wrote:</div><br class="gmail_msg m_-3270298684112585567m_2654877915551015279m_-8823961904448155070m_3398721641444251452Apple-interchange-newline"><div class="gmail_msg">You get compile time checking automatically when we can use c++14 though. If you use it with a string literal, you'll get compile time checking, otherwise you won’t.<br class="gmail_msg"></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div class="gmail_msg" style="word-wrap:break-word"><div class="gmail_msg"><div class="gmail_msg">I understand that, but that doesn’t really address my concerns.</div></div></div><div class="gmail_msg" style="word-wrap:break-word"><div class="gmail_msg"><br class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg">Here's a different example though. Suppose you're writing a tool which prints formatted output, and the field width is specified by the user.</div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div><br class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg">Now you NEED to build the format string at runtime, there's no other way</div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div class="gmail_msg" style="word-wrap:break-word"><div class="gmail_msg">Maybe the problem is using a string to format this in the first place.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">For example, you could wrap the object you want to print with an adaptor in charge of padding to the right till you reach the column width.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">format(“{0}”, rPad(col_width, my_object));</div></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div>FWIW I do think that literal format strings will handle 90% or more of uses. I just don't see the benefit of needlessly banning the other cases. Because all that's going to happen is someone is going to resort to using snprintf etc, which is exactly the problem I'm trying to solve.</div></div></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">Sorry but you’re totally missing the point. If there is a need for dynamism, this should be supported, that’s not the question. My point is that generating a string that will be parsed by a format function can’t be the only solution.</div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="gmail_msg"><div class="gmail_quote gmail_msg"> It's literally no extra effort to support runtime format strings, and it makes the library more flexible as a result.</div></div></div></blockquote><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">No: it does *not* make it more flexible than a non-string based solution that have the same functionality.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">— </div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">Mehdi</div></div></div><div style="word-wrap:break-word" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><br class="gmail_msg"><br class="gmail_msg"><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="gmail_msg"><div class="gmail_quote gmail_msg">I'm willing to start with UDLs only because I think it will get us quite far, but as soon as I need to pass a format string through an intermediate function or something like that, I will probably check in the 3 extra lines of code to add a const char* overload format function.</div><div class="gmail_quote gmail_msg"><br class="gmail_msg"></div><div class="gmail_quote gmail_msg">FWIW, there's no easy way to add compile time checking of format strings until C++14, regardless of whether use UDLs or not. So that doesn't change either way.</div></div></div></blockquote></div></div></blockquote></div>
</div></blockquote></div></div></blockquote></div></blockquote></div>