www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - isBidirectionalRange fails for unknown reasons

reply Jack Stouffer <jack jackstouffer.com> writes:
I'm trying to add a ReferenceBidirectionalRange range type to 
std.internal.test.dummyrange so I can test some range code I'm 
writing, but I've hit a wall and I'm not sure why. For some 
reason, the isBidirectionalRange check fails even though back and 
popBack are present. Any help here would be appreciated.

the code:
============================
import std.range;

class ReferenceInputRange(T)
{
     import std.array : array;

     this(Range)(Range r) if (isInputRange!Range) { _payload = 
array(r); }
     final  property ref T front(){ return _payload.front; }
     final void popFront(){ _payload.popFront(); }
     final  property bool empty(){ return _payload.empty; }
     protected T[] _payload;
}

class ReferenceForwardRange(T) : ReferenceInputRange!T
{
     this(Range)(Range r) if (isInputRange!Range) { super(r); }
     final  property ReferenceForwardRange save()
     {return new ReferenceForwardRange!T( _payload); }
}

class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T
{
     this(Range)(Range r) if (isInputRange!Range) { super(r); }
     final  property ref T back(){ return _payload.back; }
     final void popBack(){ _payload.popBack(); }
}

unittest
{
     static assert(isInputRange!(ReferenceInputRange!int)); // 
works
     static assert(isForwardRange!(ReferenceForwardRange!int)); // 
works
     static 
assert(isBidirectionalRange!(ReferenceBidirectionalRange!int)); 
//fails
}
Dec 16 2015
next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 16 December 2015 at 20:43:02 UTC, Jack Stouffer 
wrote:
 unittest
 {
     static assert(isInputRange!(ReferenceInputRange!int)); // 
 works
     static assert(isForwardRange!(ReferenceForwardRange!int)); 
 // works
     static 
 assert(isBidirectionalRange!(ReferenceBidirectionalRange!int)); 
 //fails
 }
Also, this works just fine ================= unittest { auto a = new ReferenceBidirectionalRange!int([1,2]); a.popBack(); a.back.writeln; // prints 1 }
Dec 16 2015
prev sibling next sibling parent reply anonymous <anonymous example.com> writes:
On 16.12.2015 21:43, Jack Stouffer wrote:
 I'm trying to add a ReferenceBidirectionalRange range type to
 std.internal.test.dummyrange so I can test some range code I'm writing,
 but I've hit a wall and I'm not sure why. For some reason, the
 isBidirectionalRange check fails even though back and popBack are
 present. Any help here would be appreciated.
[...]
 class ReferenceForwardRange(T) : ReferenceInputRange!T
 {
      this(Range)(Range r) if (isInputRange!Range) { super(r); }
      final  property ReferenceForwardRange save()
      {return new ReferenceForwardRange!T( _payload); }
 }

 class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T
 {
      this(Range)(Range r) if (isInputRange!Range) { super(r); }
      final  property ref T back(){ return _payload.back; }
      final void popBack(){ _payload.popBack(); }
 }
The `.save` primitive of forward ranges must return the very same type that the range has. But your ReferenceBidirectionalRange!T.save returns a ReferenceForwardRange!T, because it's inherited. That makes isForwardRange!(ReferenceBidirectionalRange!T) fail, and everything that depends on it. You can override `save` in ReferenceBidirectionalRange or try something clever like using a template this parameter: property auto save(this This)() {return new This( _payload);}
Dec 16 2015
parent Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 16 December 2015 at 21:40:44 UTC, anonymous wrote:
 The `.save` primitive of forward ranges must return the very 
 same type that the range has. But your 
 ReferenceBidirectionalRange!T.save returns a 
 ReferenceForwardRange!T, because it's inherited. That makes 
 isForwardRange!(ReferenceBidirectionalRange!T) fail, and 
 everything that depends on it.

 You can override `save` in ReferenceBidirectionalRange or try 
 something clever like using a template this parameter:

  property auto save(this This)() {return new This( _payload);}
Thanks! That did the trick.
Dec 16 2015
prev sibling parent Jakob Ovrum <jakobovrum gmail.com> writes:
On Wednesday, 16 December 2015 at 20:43:02 UTC, Jack Stouffer 
wrote:
 ...
You can also use return type covariance: class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T { this(Range)(Range r) if (isInputRange!Range) { super(r); } final override property typeof(this) save() { return new typeof(this)(_payload); } final property ref T back(){ return _payload.back; } final void popBack(){ _payload.popBack(); } } ReferenceBidirectionalRange!T is a subtype of ReferenceForwardRange!T, so the override is legal.
Dec 16 2015