Thread overview
std.format range with compound format specifiers?
November 19, 2019
I know I can format a range with a format string that contains %(%s, %). And this results in a nice comma separated list for each item.

But what about an item that has a not-so-cookie-cutter format? Like for instance a name/value field:

struct NV
{
  string name;
  int value;
}

If I want to print one of these, I can do:

format("%s: %s", nv.name, nv.value);

If I wanted to print a range of these, let's say:

auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];

How can I have it come out like:

Steve: 1, George: 500, Adam: -5

Do I have to define a toString method in the NV struct? Is there not another way besides doing this?

-Steve
November 20, 2019
On Tuesday, 19 November 2019 at 21:50:08 UTC, Steven Schveighoffer wrote:
> I know I can format a range with a format string that contains %(%s, %). And this results in a nice comma separated list for each item.
>
> But what about an item that has a not-so-cookie-cutter format? Like for instance a name/value field:
>
> struct NV
> {
>   string name;
>   int value;
> }
>
> If I want to print one of these, I can do:
>
> format("%s: %s", nv.name, nv.value);
>
> If I wanted to print a range of these, let's say:
>
> auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];
>
> How can I have it come out like:
>
> Steve: 1, George: 500, Adam: -5
>
> Do I have to define a toString method in the NV struct? Is there not another way besides doing this?
>
> -Steve

In cases where I have some aggregate data, but I don't feel like writing a custom toString method, I often wrap the data in a Tuple and use its [1] %(inner%) or %(inner%|sep%) format specifiers. Here's an example:

import std;
void main()
{
    {
        alias NV = tuple;
        auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];
        writefln("%(%(%s: %s%), %)", arr);
    }

    {
        static struct NV
        {
            string name;
            int value;
        }
        auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];
        writefln("%(%(%s: %s%), %)", arr.map!(obj => obj.tupleof.tuple));
    }
}

In this case, from outside to inside, I am first formatting the range and then for each tuple I am formatting its fields one by one.

If for exmaple I want to format a tuple with 3 double, each one of them with a different number of digits after the decimal point, I could do:
"%(%.1f %.2f %.3f%)".writefln(tuple(1.5, 1.25, 1.125));

If on the other hand I want to format all tuple elements the same, I would use this scheme:
"%(%.1f%| %)".writefln(tuple(1.5, 1.25, 1.125));

I think we should extend std.format with support for using the same tuple formatting specifier as std.typecons.Tuple, but for structs and possibly classes, as I find it quite useful.

[1]: https://dlang.org/phobos/std_typecons#.Tuple.toString
November 19, 2019
On 11/19/19 7:28 PM, Petar Kirov [ZombineDev] wrote:
> 
> In cases where I have some aggregate data, but I don't feel like writing a custom toString method, I often wrap the data in a Tuple and use its [1] %(inner%) or %(inner%|sep%) format specifiers. Here's an example:
> 
> import std;
> void main()
> {
>      {
>          alias NV = tuple;
>          auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];
>          writefln("%(%(%s: %s%), %)", arr);
>      }
> 
>      {
>          static struct NV
>          {
>              string name;
>              int value;
>          }
>          auto arr = [NV("Steve", 1), NV("George", 500), NV("Adam", -5)];
>          writefln("%(%(%s: %s%), %)", arr.map!(obj => obj.tupleof.tuple));
>      }
> }
> 
> In this case, from outside to inside, I am first formatting the range and then for each tuple I am formatting its fields one by one.

Sweet! This is exactly what I was looking for.

> If for exmaple I want to format a tuple with 3 double, each one of them with a different number of digits after the decimal point, I could do:
> "%(%.1f %.2f %.3f%)".writefln(tuple(1.5, 1.25, 1.125));

Nice. I think this should work well for me.

> I think we should extend std.format with support for using the same tuple formatting specifier as std.typecons.Tuple, but for structs and possibly classes, as I find it quite useful.

Yes. At least the mechanism you describe should be pasted into formattedWrite's spec as I had no idea about it, and I would not think to look at tuple docs for the answer.

A format spec that indicates formattedWrite should use tupleof and treat it the same would be nice instead of having to do map.tupleof.tuple.

-Steve