Thread overview
std.range.put?
May 21, 2012
simendsjo
May 21, 2012
jerro
May 21, 2012
jerro
May 21, 2012
Shouldn't the following work?

import std.range;
import std.stdio;

void main() {
    int[] a;
    a.reserve(10);
    //a.put(1); // Attempting to fetch the front of an empty array of int
    a.length = 1;
    writeln(a.length); // 1
    a.put(2);
    writeln(a.length); // 0 - what?
    writeln(a); // [] - come on!

    char[] b;
    //b.put('a'); // range.d(615): Error: static assert  "Cannot put a char into a char[]"
}
May 21, 2012
On Monday, 21 May 2012 at 11:26:33 UTC, simendsjo wrote:
> Shouldn't the following work?
>
> import std.range;
> import std.stdio;
>
> void main() {
>     int[] a;
>     a.reserve(10);
>     //a.put(1); // Attempting to fetch the front of an empty array of int
>     a.length = 1;
>     writeln(a.length); // 1
>     a.put(2);
>     writeln(a.length); // 0 - what?
>     writeln(a); // [] - come on!
>
>     char[] b;
>     //b.put('a'); // range.d(615): Error: static assert  "Cannot put a char into a char[]"
> }

Input ranges are supposed to work like that when use as output
range. You could change that by also defining a put member for
them, but I don't think doing that would be a good idea. The
current behavior allows you to fill an input range using a
function that takes an output range. For example you can do
the following with an array:


auto a = [4, 3, 2, 1, 0];
copy([0,1,2], a);
writeln(a); // prints [0, 1, 2, 1, 0]

If an array had a put member that would append to it, this
would print [4, 3, 2, 1, 0, 0, 1, 2]. I think it is better
to have to explicitly state that you want to append to an
array. It should be possible to use RefAppender for that:

copy([0, 1, 2], appender(&a)); // error

This currently doesn't work (I think that because RefAppender implements
put through opDispatch and constraint for range.put checks for put member
using hasMember). You could write your own function to work around that:

auto output(T)(ref T[] arr)
{
    static struct R
    {
        T[]* arr;
        void put(int v){ arr ~= v; }
    }
    return R(&arr);
}

auto a = [4, 3, 2, 1, 0];
copy([0,1,2], output(a));
writeln(a); // prints [4, 3, 2, 1, 0, 0, 1, 2]

May 21, 2012
> void put(int v){ arr ~= v; }

should be

void put(T v){ *arr ~= v; }
May 23, 2012
On Mon, 21 May 2012 07:26:32 -0400, simendsjo <simendsjo@gmail.com> wrote:

> Shouldn't the following work?
>
> import std.range;
> import std.stdio;
>
> void main() {
>      int[] a;
>      a.reserve(10);
>      //a.put(1); // Attempting to fetch the front of an empty array of int
>      a.length = 1;
>      writeln(a.length); // 1
>      a.put(2);
>      writeln(a.length); // 0 - what?
>      writeln(a); // [] - come on!
OK, here is why:

put(R, v) has three modus operandi:

1. R is an input range with an lvalue front().
2. R is a function/delegate that accepts a v
3. R implements the method put(v)

slices fit into category one.  In this case, guess what happens?

R.front = v;
R.popFront();

Why?  Think of R as a *buffer* that is *pre-allocated* and needs to be filled.  This is what put is trying to do.

What you want is std.array.Appender, which defines the method put, which *appends* data to the end instead of overwriting it.

>      char[] b;
>      //b.put('a'); // range.d(615): Error: static assert  "Cannot put a char into a char[]"
> }

This is just phobos being its usual nasty self claiming that char[] is not an array of char, but actually a range of dchar.  If I only had a nickel every time someone ran into this "feature"... I'd probably have about $5 by now ;)  It's one of the worst designs of Phobos.

-Steve