Thread overview
refRange and @disable this(this);
Sep 14, 2016
Jerry
Sep 14, 2016
Jerry
Sep 14, 2016
Jonathan M Davis
Sep 14, 2016
Mathias Lang
Sep 15, 2016
Jacob Carlborg
September 14, 2016
I got a range which disables copy construction and I want to loop the range within another loop using the same range.
So I thought I can mark the struct range with @disable this(this) and then use refRange to initialize the loop.

So with something like this:

void main()
{	
	auto valueRange = FooRange("123");
	foreach(ch; refRange(&valueRange))
		writeln(ch);
}


struct FooRange {
	@disable this();
	@disable this(this);
	this(string str) {
		this.str = str;
	}
	
	@property bool empty() { return str.empty; }
	@property dchar front() { return str.front; }
	void popFront() { str.popFront; }
	
private:
	string str;
}


But I get compile time errors messages saying:
std/range/package.d(8155,23): Error: struct app.FooRange is not copyable because it is annotated with @disable

It feels strange that refRange ever want to copy.
Bug or feature?

September 14, 2016
On Wednesday, 14 September 2016 at 12:39:16 UTC, Jerry wrote:
> It feels strange that refRange ever want to copy.
> Bug or feature?

Or more specificly, shouldn't save only be defined if the range defines it instead of using copy? Which is presume is the problem.
September 14, 2016
On Wednesday, September 14, 2016 12:39:16 Jerry via Digitalmars-d wrote:
> I got a range which disables copy construction and I want to loop
> the range within another loop using the same range.
> So I thought I can mark the struct range with @disable this(this)
> and then use refRange to initialize the loop.
>
> So with something like this:
>
> void main()
> {
>   auto valueRange = FooRange("123");
>   foreach(ch; refRange(&valueRange))
>       writeln(ch);
> }
>
>
> struct FooRange {
>   @disable this();
>   @disable this(this);
>   this(string str) {
>       this.str = str;
>   }
>
>   @property bool empty() { return str.empty; }
>   @property dchar front() { return str.front; }
>   void popFront() { str.popFront; }
>
> private:
>   string str;
> }
>
>
> But I get compile time errors messages saying: std/range/package.d(8155,23): Error: struct app.FooRange is not copyable because it is annotated with @disable
>
> It feels strange that refRange ever want to copy.
> Bug or feature?

It's opAssign does a copy. The rationale is given in its documentation:

http://dlang.org/phobos/std_range.html#.RefRange.opAssign

The result of that is that the range you give it needs to be copyable. But the reality of the matter is that ranges in general expect to be copyable, and range-based code is going to have a tendency to fall flat on its face if you try to define a range that's non-copyable. I'm actually kind of surprised that such a range passes isInputRange given that it tests this line:

    R r = R.init;

But I guess that it works, because you didn't explicitly disable opAssign (though at least sometimes, disabling the postblit constructor seems to disable opAssign from what I recall).

If want to guarantee that a range's state is never copied, and you're creating a range specifically for this, you might as well just make it a class and force it to have reference semantics. RefRange was intended for cases where you have a range that works normally, but you need to pass it to some code and have the the state of the range be updated rather than having a copy updated. It wasn't intended that it be used for a range that you wanted to always be a reference type, since if you want that, you can just declare a range that's a reference type.

- Jonathan M Davis

September 14, 2016
You should be able to work around this by using `for` loop instead of
`foreach`.
IMO that's a design bug in `foreach`:
https://issues.dlang.org/show_bug.cgi?id=15413

2016-09-14 14:39 GMT+02:00 Jerry via Digitalmars-d < digitalmars-d@puremagic.com>:

> I got a range which disables copy construction and I want to loop the
> range within another loop using the same range.
> So I thought I can mark the struct range with @disable this(this) and then
> use refRange to initialize the loop.
>
> So with something like this:
>
> void main()
> {
>         auto valueRange = FooRange("123");
>         foreach(ch; refRange(&valueRange))
>                 writeln(ch);
> }
>
>
> struct FooRange {
>         @disable this();
>         @disable this(this);
>         this(string str) {
>                 this.str = str;
>         }
>
>         @property bool empty() { return str.empty; }
>         @property dchar front() { return str.front; }
>         void popFront() { str.popFront; }
>
> private:
>         string str;
> }
>
>
> But I get compile time errors messages saying: std/range/package.d(8155,23): Error: struct app.FooRange is not copyable because it is annotated with @disable
>
> It feels strange that refRange ever want to copy.
> Bug or feature?
>
>


September 15, 2016
On 2016-09-14 14:39, Jerry wrote:
> I got a range which disables copy construction and I want to loop the
> range within another loop using the same range.
> So I thought I can mark the struct range with @disable this(this) and
> then use refRange to initialize the loop.
>
> So with something like this:
>
> void main()
> {
>     auto valueRange = FooRange("123");
>     foreach(ch; refRange(&valueRange))
>         writeln(ch);
> }
>
>
> struct FooRange {
>     @disable this();
>     @disable this(this);
>     this(string str) {
>         this.str = str;
>     }
>
>     @property bool empty() { return str.empty; }
>     @property dchar front() { return str.front; }
>     void popFront() { str.popFront; }
>
> private:
>     string str;
> }
>
>
> But I get compile time errors messages saying:
> std/range/package.d(8155,23): Error: struct app.FooRange is not copyable
> because it is annotated with @disable
>
> It feels strange that refRange ever want to copy.
> Bug or feature?

As a workaround you can take the address of the range and use std.algorithm.each:

void main()
{
    auto valueRange = FooRange("123");
    (&valueRange).each!(ch => writeln(ch));
}

With a convenience function:

T* ptr(ref T t){ return &t; }

void main()
{
    auto valueRange = FooRange("123");
    valueRange.ptr.each!(ch => writeln(ch));
}

-- 
/Jacob Carlborg