Question about OutputRange and std.range: put

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jan 16 08:14:56 PST 2016


On Saturday, January 16, 2016 12:11:11 Uranuz via Digitalmars-d-learn wrote:
> Hello to forum readers!
> I have a question about using OutputRange and std.range: put. I
> have the following code snippet to illustrate my question:
>
> import std.range, std.stdio, std.string;
>
> void main()
> {
>   string greating = "Hello, " ;
>   string username = "Bob";
>
>   put(greating, username);
>   put(greating, "!");
>
>   writeln(greating);
> }
>
> It doesn't compile. It says following:
>
> Compilation output:
> /opt/compilers/dmd2/include/std/range/primitives.d(335): Error:
> static assert  "Cannot put a string into a string."
> /d52/f530.d(8):        instantiated from here: put!(string,
> string)
>
> Documentation about std.range.put says that one of code snippets,
> where *put* applies is when second argument is array of elements
> (If I understand it correctly with my knowledge of English).
> Especially the following line is there in doc for usage scenario:
>
> r.doPut([ e ]);   R specifically accepts an E[].
>
> Can I put range or array f elements as second argument of put or
> it works only at per element basis? I think writing multiple
> items at a time should be more effective but maybe it's not
> supported for OutputRange? Could someone explain?

There are a few problems here. First off, when put is used with an array, it
fills the array. It doesn't append to it. So, you can't use a string as an
output range, since its elements are immutable. Here's an example with
int[]:

    auto arr = new int[](5);
    assert(arr == [0, 0, 0, 0, 0]);
    auto output = arr;

    put(output, 1);
    assert(arr == [1, 0, 0, 0, 0]);
    assert(output == [0, 0, 0, 0]);

    put(output, [2, 3, 4]);
    assert(arr == [1, 2, 3, 4, 0]);
    assert(output == [0]);

Add yes, put will take either an element or a range of elements - which is
why it's generally a bad idea to use put with UFCS (because an overloaded
put is unlikely to have all of the overloads that the free function
supports, but it will be used by the free function where appropriate).

Now, characters get a bit more interesting due to Unicode concerns. Narrow
strings - i.e. arrays of char or wchar - are not considered output ranges,
similar to how hasLength!string will return false (since with char (UTF-8)
and wchar (UTF-16) a single code point will not necessarily fit within a
single code unit, whereas with dchar (UTF-32), they're one and the same).
Whether that's how it _should_ work is debatable - particularly since the
main reason to not allow it is because with a short enough char[] or
wchar[], you can't guarantee that a dchar will fit, but you can't guarantee
that an input range of characters will fit either (and yet put accepts
those). But regardless, char[] and wchar[] are not currently considered
output ranges. So, if you want to use an array of characters as an output
range, it'll have to be dchar[].

Now, odds are what you really want is to use Appender. It _does_ append when
inserting elements rather than fill, and it _can_ be used with narrow
strings - including string. e.g.

    auto output = appender!string();
    assert(output.data.empty);
    output.put("hello");
    assert(output.data == "hello");

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list