Thread overview
Unexpected issue with std.format
Feb 01, 2020
Saurabh Das
Feb 01, 2020
Saurabh Das
Feb 01, 2020
Saurabh Das
February 01, 2020
I faced this issue while working with custom formatting for a struct. I have reduced the error down to this test program:

import std.format, std.stdio, std.array;

struct Test1
{
    void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
    {
        pragma(msg, "Test1 function compiled with W=" ~ W.stringof);
        // formatValue(w, this, fmt);
    }
}

struct Test2
{
    void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
    {
        pragma(msg, "Test2 function compiled with W=" ~ W.stringof);
        formatValue(w, this, fmt);
    }
}

void main()
{
    Test1 t1;
    Test2 t2;

    Appender!string writer;
    auto ff = singleSpec("%s");

    formatValue(writer, t1, ff);
    formatValue(writer, t2, ff);
}

When compiled, the output is:

Test1 function compiled with W=S
Test1 function compiled with W=Appender!string
Test2 function compiled with W=S

1. Why was Test2 never compiled with W=Appender!string?
2. What is "S"?

Essentially, my custom struct was not being formatted using the toString method that I had written. Reducing the issue, it seems like a call to formatValue with the same type caused the issue. If someone can explain what I am doing wrong here, it would really help a lot.

Thanks,
Saurabh

February 01, 2020
On Saturday, 1 February 2020 at 13:39:34 UTC, Saurabh Das wrote:
> I faced this issue while working with custom formatting for a struct. I have reduced the error down to this test program:
>
> [...]

PS: Currently using DMD64 D Compiler v2.090.0
February 01, 2020
On 2/1/20 8:39 AM, Saurabh Das wrote:
> I faced this issue while working with custom formatting for a struct. I have reduced the error down to this test program:
> 
> import std.format, std.stdio, std.array;
> 
> struct Test1
> {
>      void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
>      {
>          pragma(msg, "Test1 function compiled with W=" ~ W.stringof);
>          // formatValue(w, this, fmt);
>      }
> }
> 
> struct Test2
> {
>      void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
>      {
>          pragma(msg, "Test2 function compiled with W=" ~ W.stringof);
>          formatValue(w, this, fmt);
>      }
> }
> 
> void main()
> {
>      Test1 t1;
>      Test2 t2;
> 
>      Appender!string writer;
>      auto ff = singleSpec("%s");
> 
>      formatValue(writer, t1, ff);
>      formatValue(writer, t2, ff);
> }
> 
> When compiled, the output is:
> 
> Test1 function compiled with W=S
> Test1 function compiled with W=Appender!string
> Test2 function compiled with W=S
> 
> 1. Why was Test2 never compiled with W=Appender!string?
> 2. What is "S"?
> 
> Essentially, my custom struct was not being formatted using the toString method that I had written. Reducing the issue, it seems like a call to formatValue with the same type caused the issue. If someone can explain what I am doing wrong here, it would really help a lot.
> 
> Thanks,
> Saurabh
> 

Something very weird is happening.

I switched to fullyQualifiedName!W, and I get *no output*.

The "S" comes from hasToString here:https://github.com/dlang/phobos/blob/9fe5cd354f0166b11d32a5c1214932757d8e7eba/std/format.d#L3876-L3899

I tried copying the implementation to a local file, and as expected, I get customPutWriterFormatSpec for both types.

But it's only calling one of them in the implementation.

I think the only true way to diagnose this is to instrument std.format and see what it's doing with more pragma(msg) calls. Don't have the time right now.

-Steve
February 01, 2020
On Saturday, 1 February 2020 at 15:16:41 UTC, Steven Schveighoffer wrote:
> On 2/1/20 8:39 AM, Saurabh Das wrote:
>> I faced this issue while working with custom formatting for a struct. I have reduced the error down to this test program:
>> 
>> import std.format, std.stdio, std.array;
>> 
>> struct Test1
>> {
>>      void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
>>      {
>>          pragma(msg, "Test1 function compiled with W=" ~ W.stringof);
>>          // formatValue(w, this, fmt);
>>      }
>> }
>> 
>> struct Test2
>> {
>>      void toString(W, C)(ref W w, scope const ref FormatSpec!C fmt)
>>      {
>>          pragma(msg, "Test2 function compiled with W=" ~ W.stringof);
>>          formatValue(w, this, fmt);
>>      }
>> }
>> 
>> void main()
>> {
>>      Test1 t1;
>>      Test2 t2;
>> 
>>      Appender!string writer;
>>      auto ff = singleSpec("%s");
>> 
>>      formatValue(writer, t1, ff);
>>      formatValue(writer, t2, ff);
>> }
>> 
>> When compiled, the output is:
>> 
>> Test1 function compiled with W=S
>> Test1 function compiled with W=Appender!string
>> Test2 function compiled with W=S
>> 
>> 1. Why was Test2 never compiled with W=Appender!string?
>> 2. What is "S"?
>> 
>> Essentially, my custom struct was not being formatted using the toString method that I had written. Reducing the issue, it seems like a call to formatValue with the same type caused the issue. If someone can explain what I am doing wrong here, it would really help a lot.
>> 
>> Thanks,
>> Saurabh
>> 
>
> Something very weird is happening.
>
> I switched to fullyQualifiedName!W, and I get *no output*.
>
> The "S" comes from hasToString here:https://github.com/dlang/phobos/blob/9fe5cd354f0166b11d32a5c1214932757d8e7eba/std/format.d#L3876-L3899
>
> I tried copying the implementation to a local file, and as expected, I get customPutWriterFormatSpec for both types.
>
> But it's only calling one of them in the implementation.
>
> I think the only true way to diagnose this is to instrument std.format and see what it's doing with more pragma(msg) calls. Don't have the time right now.
>
> -Steve

Thanks for the lead. To exemplify Steve's observation:

import std.format, std.stdio, std.array, std.range;

struct Test3
{
    void toString(W, C)(ref W w,  scope const ref FormatSpec!C fmt)
    {
        import std.traits;
        pragma(msg, "A: Test2 function compiled with W=" ~ fullyQualifiedName!W.stringof);
        pragma(msg, "B: Test2 function compiled with W=" ~ W.stringof);
    }
}

void main()
{
    Test3 t3;

    Appender!string writer;
    auto ff = singleSpec("%s");

    formatValue(writer, t3, ff);
}

Gives an output during compilation:
B: Test2 function compiled with W=S


Saurabh