Thread overview
Why does templated interface function return something different than final function?
Jul 18, 2018
Timoses
Jul 18, 2018
Timoses
Aug 06, 2018
Timoses
Aug 08, 2018
Timoses
July 18, 2018
Why is the interface templated function not also returning the class C toString return value "in C"??

	interface iface
	{
		void toString(scope void delegate(const(char)[]) sink) const;

		final string convert() inout
		{
			import std.conv;
			// assert(std.conv.to!string(this) == "in C"); // fails!
			return std.conv.to!string(this);
		}

		final string convert2() const
		{
			import std.conv;
			assert(std.conv.to!string(this) == "in C");
			return std.conv.to!string(this);
		}
	}

	class C : iface
	{
		void toString(scope void delegate(const(char)[]) sink) const
		{
			sink("in C");
		}
	}

	void main ()
	{
		iface i = new C();
		import std.stdio;
		writeln(i.convert); // "app.C"
		writeln(i.convert2()); // "in C"
	}

It seems like `inout` triggers some odd behaviour??
July 18, 2018
On Wednesday, 18 July 2018 at 11:09:12 UTC, Timoses wrote:
> Why is the interface templated function not also returning the class C toString return value "in C"??
>
> 	interface iface
> 	{
> 		void toString(scope void delegate(const(char)[]) sink) const;
>
> 		final string convert() inout
> 		{
> 			import std.conv;
> 			// assert(std.conv.to!string(this) == "in C"); // fails!
> 			return std.conv.to!string(this);
> 		}
>
> 		final string convert2() const
> 		{
> 			import std.conv;
> 			assert(std.conv.to!string(this) == "in C");
> 			return std.conv.to!string(this);
> 		}
> 	}
>
> 	class C : iface
> 	{
> 		void toString(scope void delegate(const(char)[]) sink) const
> 		{
> 			sink("in C");
> 		}
> 	}
>
> 	void main ()
> 	{
> 		iface i = new C();
> 		import std.stdio;
> 		writeln(i.convert); // "app.C"
> 		writeln(i.convert2()); // "in C"
> 	}
>
> It seems like `inout` triggers some odd behaviour??

Sorry, I experimented a bit and forgot to change the topic to something more fitting, e.g.
"Why does inout struct function return different results?"
August 02, 2018
On 7/18/18 7:09 AM, Timoses wrote:
> Why is the interface templated function not also returning the class C toString return value "in C"??
> 
>      interface iface
>      {
>          void toString(scope void delegate(const(char)[]) sink) const;
> 
>          final string convert() inout
>          {
>              import std.conv;
>              // assert(std.conv.to!string(this) == "in C"); // fails!
>              return std.conv.to!string(this);
>          }
> 
>          final string convert2() const
>          {
>              import std.conv;
>              assert(std.conv.to!string(this) == "in C");
>              return std.conv.to!string(this);
>          }
>      }
> 
>      class C : iface
>      {
>          void toString(scope void delegate(const(char)[]) sink) const
>          {
>              sink("in C");
>          }
>      }
> 
>      void main ()
>      {
>          iface i = new C();
>          import std.stdio;
>          writeln(i.convert); // "app.C"
>          writeln(i.convert2()); // "in C"
>      }
> 
> It seems like `inout` triggers some odd behaviour??

Looking at the AST, it appears that toImpl doesn't recognize what inout(iface) is:

toImpl!(string, inout(iface))
{
	@system string toImpl(ref inout(iface) value)
	{
		import std.array : appender;
		import std.format : FormatSpec, formatValue;
		Appender!string w = appender();
		FormatSpec!char f = FormatSpec;
		formatValue(w, value, f);
		return w.data();
	}

}

Vs. the nice neat call for const(iface)

toImpl!(string, const(iface))
{
	@system string toImpl(const(iface) value)
	{
		return toStr(value);
	}

}

Note the ref there, too. This means it can't cast to const. I wonder if that's an issue.

-Steve
August 06, 2018
On Thursday, 2 August 2018 at 20:35:57 UTC, Steven Schveighoffer wrote:
>
> Looking at the AST, it appears that toImpl doesn't recognize what inout(iface) is:
>
> toImpl!(string, inout(iface))
> {
> 	@system string toImpl(ref inout(iface) value)
> 	{
> 		import std.array : appender;
> 		import std.format : FormatSpec, formatValue;
> 		Appender!string w = appender();
> 		FormatSpec!char f = FormatSpec;
> 		formatValue(w, value, f);
> 		return w.data();
> 	}
>
> }
>
> Vs. the nice neat call for const(iface)
>
> toImpl!(string, const(iface))
> {
> 	@system string toImpl(const(iface) value)
> 	{
> 		return toStr(value);
> 	}
>
> }
>
> Note the ref there, too. This means it can't cast to const. I wonder if that's an issue.
>
> -Steve

Thanks for the insight. To me it sounds like std.conv `toImpl` doesn't properly handle inout types in this case.
August 08, 2018
On Monday, 6 August 2018 at 14:27:01 UTC, Timoses wrote:
> On Thursday, 2 August 2018 at 20:35:57 UTC, Steven Schveighoffer wrote:
>>
>> Looking at the AST, it appears that toImpl doesn't recognize what inout(iface) is:
>>
>> toImpl!(string, inout(iface))
>> {
>> 	@system string toImpl(ref inout(iface) value)
>> 	{
>> 		import std.array : appender;
>> 		import std.format : FormatSpec, formatValue;
>> 		Appender!string w = appender();
>> 		FormatSpec!char f = FormatSpec;
>> 		formatValue(w, value, f);
>> 		return w.data();
>> 	}
>>
>> }
>>
>> Vs. the nice neat call for const(iface)
>>
>> toImpl!(string, const(iface))
>> {
>> 	@system string toImpl(const(iface) value)
>> 	{
>> 		return toStr(value);
>> 	}
>>
>> }
>>
>> Note the ref there, too. This means it can't cast to const. I wonder if that's an issue.
>>
>> -Steve
>
> Thanks for the insight. To me it sounds like std.conv `toImpl` doesn't properly handle inout types in this case.

Well, my "workaround" now is to simply cast the inout type to const before passing to std.conv.to ...


I've experimented a bit more and compiled it a bit together.

    import std.stdio;
    import std.conv : to;

    interface I
    {
        void toString(scope void delegate(const(char)[]) sink) const;

        final void printI()
        {
            writeln(this.to!string); // this is class A
        }
        final void printIinout() inout
        {
            writeln(this.to!string); // app.A
        }
    }

    class A : I
    {
        void print()
        {
            writeln(this.to!string); // this is class A
        }
        // Compilation error
        // std\format.d(3890,13): Error: template instance `std.format.formatObject!(Appender!string, inout(A), char)` does not match template declaration `formatObject(Writer, T, Char)(ref Writer w, ref T val, ref const FormatSpec!Char f) if (hasToString!(T, Char))`
        /*void printinout() inout
        {
            writeln(this.to!string);
        }*/
        override void toString(scope void delegate(const(char)[]) sink) const
        {
            sink("this is class A");
        }
    }

    unittest
    {
        I i = new A();
        i.printI();
        i.printIinout();

        A a = new A();
        a.print();
        //a.printinout();
    }

It seems inconsistent to me. What do you think? Should I open a bug report for this?
Also the compilation error should not occur, should it?