[llvm-dev] RFC: General purpose type-safe formatting library

Zachary Turner via llvm-dev llvm-dev at lists.llvm.org
Wed Oct 12 21:45:59 PDT 2016


Perhaps I should elaborate on something I said in the original post.

"There are other ways to customize the formatting behavior, but I'll keep
going with some more "

What I meant here is that there I currently have a two-stage lookup for a
format provider.

1. If the type you passed in is a class, and it contains a format method
with the appropriate signature, that method is invoked.
2. Otherwise, it looks for a specialization of llvm::format_provider<T>
with a format method of the appropriate signature.

So in your range example, it would be perfectly reasonable to write:

template<typename Iter>
class Range {
  Iter Begin;
  Iter End;
  void format(raw_ostream &S, int Align, StringRef Style) {
  }
};

template<typename T>
Range<std::iterator_traits<T>::const_iterator> format_range(T &&t) {
  return Range<std::iterator_traits<T>::const_iterator>(std::begin(t),
std::end(t));
}

and then write:

std::vector<int> X = {1, 2, 3};
os.format("{0: }", format_range(X));

And just to be clear, I think that syntax has clear advantages.  What I
don't like is this:

os << "blah blah" << format<std::milli>(end-start) << "blah blah"

I would much prefer to write that

os.format("blah blah {0:ms} blah blah", end-start);

On Wed, Oct 12, 2016 at 9:32 PM Zachary Turner <zturner at google.com> wrote:

> 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
>
> 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
>
> print("{0:,}", Range(s.begin(), s.begin()+20))
>
> This way you have the freedom to display it multiple times with different
> presentation. Eg
>
> print("{0:,} {0: }")
> On Wed, Oct 12, 2016 at 9:16 PM Mehdi Amini <mehdi.amini at apple.com> wrote:
>
> On Oct 12, 2016, at 8:33 PM, Zachary Turner <zturner at google.com> wrote:
>
> 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.
>
>
> 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.
>
> 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:
>
> /* Format string is {eltid, separator, <range>} */
> print(“{0:,<10-20>}”,  /* std::vector<int> */. v);
>
> And having to actually generate the format string in the first place
>
> std::string format = format_string(“\{0:,<{0}-{1}>\}”, /* begin */ 10, /*
> end */ 20);
>
> I rather have something like
>
> print(“{0}”, Range(“, ", v.begin()+10, v.begin()+20));
>
>
>   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.
>
> 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.
>
> 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.
>
>
> 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.
>
>
> I am not convinced that just because previous attempts didn’t success,
> we’re stuck forever with printf.
>
> At this point I’m not it is worth continuing the discussion, we can just
> agree to disagree on the principle.
>
>> Mehdi
>
>
> On Wed, Oct 12, 2016 at 8:19 PM Mehdi Amini <mehdi.amini at apple.com> wrote:
>
> On Oct 12, 2016, at 8:07 PM, Zachary Turner <zturner at google.com> wrote:
>
> On Wed, Oct 12, 2016 at 12:40 PM Mehdi Amini <mehdi.amini at apple.com>
> wrote:
>
> On Oct 12, 2016, at 12:35 PM, Zachary Turner <zturner at google.com> wrote:
>
> 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.
>
>
> I understand that, but that doesn’t really address my concerns.
>
>
> 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.
>
>
>
> Now you NEED to build the format string at runtime, there's no other way
>
>
> Maybe the problem is using a string to format this in the first place.
>
> 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.
>
> format(“{0}”, rPad(col_width, my_object));
>
>
> 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.
>
>
> 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.
>
>   It's literally no extra effort to support runtime format strings, and it
> makes the library more flexible as a result.
>
>
> No: it does *not* make it more flexible than a non-string based solution
> that have the same functionality.
>
>> Mehdi
>
>
>
> 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.
>
> 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.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20161013/4cfc7ef3/attachment.html>


More information about the llvm-dev mailing list