Thread overview
Output Range Problem? How to make it work?
Oct 11, 2021
apz28
Oct 11, 2021
Paul Backus
Oct 11, 2021
apz28
Oct 11, 2021
Paul Backus
October 11, 2021

import std.range.primitives: isOutputRange;

@safe:

struct Buffer
{
@safe:

    void put(char c)
	{}
    void put(scope const(char)[] s)
    {}
}

struct Foo
{
@safe:

    string toString()
	{return null;}

    ref Writer toString(Writer, Char)(return ref Writer sink)
    if (isOutputRange!(Writer, Char) && isSomeChar!Char)
    {return sink;}

    string toString(const(char)[] fmt)
    {return null;}
}

void main()
{	
    Buffer buffer;
    Foo foo;
    foo.toString(buffer);
}

/* Getting this error
onlineapp.d(34): Error: none of the overloads of toString are callable using argument types (Buffer), candidates are:
onlineapp.d(19): onlineapp.Foo.toString()
onlineapp.d(26): onlineapp.Foo.toString(const(char)[] fmt)
onlineapp.d(22): toString(Writer, Char)(return ref Writer sink)
*/

October 11, 2021

On Monday, 11 October 2021 at 00:19:44 UTC, apz28 wrote:

>

/* Getting this error
onlineapp.d(34): Error: none of the overloads of toString are callable using argument types (Buffer), candidates are:
onlineapp.d(19): onlineapp.Foo.toString()
onlineapp.d(26): onlineapp.Foo.toString(const(char)[] fmt)
onlineapp.d(22): toString(Writer, Char)(return ref Writer sink)
*/

The signature of your toString method should match one of the examples in the documentation:

void toString(Writer, Char)(ref Writer w, const ref FormatSpec!Char fmt)
void toString(Writer)(ref Writer w)
string toString();

Here is an example that works:

import std.range: put;
import std.array: appender;
import std.format: formattedWrite;

struct Foo
{
    void toString(Writer)(ref Writer writer)
    {
        put(writer, "Foo");
    }
}

void main()
{
    auto buffer = appender!string;
    Foo foo;
    formattedWrite(buffer, "%s", foo);
    assert(buffer[] == "Foo");
}

Link: https://run.dlang.io/is/dZLRuo

October 11, 2021

On Monday, 11 October 2021 at 00:37:43 UTC, Paul Backus wrote:

>

On Monday, 11 October 2021 at 00:19:44 UTC, apz28 wrote:

>

/* Getting this error
onlineapp.d(34): Error: none of the overloads of toString are callable using argument types (Buffer), candidates are:
onlineapp.d(19): onlineapp.Foo.toString()
onlineapp.d(26): onlineapp.Foo.toString(const(char)[] fmt)
onlineapp.d(22): toString(Writer, Char)(return ref Writer sink)
*/

The signature of your toString method should match one of the examples in the documentation:

void toString(Writer, Char)(ref Writer w, const ref FormatSpec!Char fmt)
void toString(Writer)(ref Writer w)
string toString();

Here is an example that works:

import std.range: put;
import std.array: appender;
import std.format: formattedWrite;

struct Foo
{
    void toString(Writer)(ref Writer writer)
    {
        put(writer, "Foo");
    }
}

void main()
{
    auto buffer = appender!string;
    Foo foo;
    formattedWrite(buffer, "%s", foo);
    assert(buffer[] == "Foo");
}

Link: https://run.dlang.io/is/dZLRuo

On Monday, 11 October 2021 at 00:37:43 UTC, Paul Backus wrote:

The subject is why the call is not allowed (format is not mention in question). Below sample is a bit more clear

import std.range.primitives : isOutputRange;
import std.traits: isSomeChar;

@safe:

struct Buffer(Char)
{
@safe:

    void put(Char c)
	{}

    void put(scope const(Char)[] s)
    {}
}

struct Foo
{
@safe:

    ref Writer outWork(Writer)(return ref Writer sink)
    if (isOutputRange!(Writer, char))
    {return sink;}

    // Remove " && isSomeChar!Char" does not make any difference
    ref Writer outFail(Writer, Char)(return ref Writer sink)
    if (isOutputRange!(Writer, Char) && isSomeChar!Char)
    {return sink;}
}

void main()
{	
    pragma(msg, isOutputRange!(Buffer!char, char)); // Print true

    Buffer!char buffer;
    Foo foo;
    foo.outWork(buffer); // OK

    foo.outFail!(Buffer!char, char)(buffer); // OK with explicit

    foo.outFail(buffer); // NOT OK
}

/* Blow is output from online compiler
true
onlineapp.d(40): Error: template onlineapp.Foo.outFail cannot deduce function from argument types !()(Buffer!char), candidates are:
onlineapp.d(25): outFail(Writer, Char)(return ref Writer sink)
*/

October 11, 2021

On Monday, 11 October 2021 at 15:57:00 UTC, apz28 wrote:

>

The subject is why the call is not allowed (format is not mention in question). Below sample is a bit more clear

[...]

>
    ref Writer outFail(Writer, Char)(return ref Writer sink)
    if (isOutputRange!(Writer, Char) && isSomeChar!Char)
    {return sink;}

[...]

>
    foo.outFail(buffer); // NOT OK

The template parameter Char does not appear anywhere in the function's parameter list, so the compiler cannot deduce it from the function's arguments.

Here is a simpler example that demonstrates the same problem:

Dest convert(Source, Dest)(Source source)
{
    return cast(Dest) source;
}

void main()
{
    double d = 123.456;
    auto result = convert(d); // Source = double, Dest = ???
}