forward range properties with alias this - how?

Ivan Kazmenko via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Wed Jul 29 16:54:27 PDT 2015


On Wednesday, 29 July 2015 at 12:25:14 UTC, Marc Schütz wrote:
> On Tuesday, 28 July 2015 at 21:25:23 UTC, Ivan Kazmenko wrote:
>> Hello,
>>
>> I wrap an array into a struct.  Then I use alias this to 
>> expose the array functionality.  Sadly, range properties of 
>> the array are not forwarded, and so I can't use the struct as 
>> an array with functions from std.algorithm and std.range.
>>
>> -----
>> import std.range, std.stdio;
>> struct S {
>> 	int[] contents;
>> 	alias contents this;
>> }
>> void main() {
>> 	S s;
>> 	writeln(hasSlicing!(S)); // false
>> }
>> -----
>>
>> I would like to be able to do that, however.
>>
>> 1. Why exactly hasSlicing (et al.) does not check the alias 
>> this-ed array when it checks the struct?
>>
>> 2. What should I do?
>>
>> The solution I can think of is to insert the 3-6 range 
>> functions which forward the functionality to the underlying 
>> array, perhaps as a mixin.
>>
>> Ivan Kazmenko.
>
> `hasSlicing` explicitly checks whether the result of the slice 
> operator has the same type as the original:
>
> https://github.com/D-Programming-Language/phobos/blob/master/std/range/primitives.d#L1499-L1500
>
> If you remove the `static assert()` and change the next line to 
> use `auto`, and do the same in the other two places in this 
> templates, it will work.

Thank you, the matter got clearer after reading the right piece 
of code and your explanation.

By the way, the documentation around these source lines always 
repeats a slightly outdated version of the unittests.  Shouldn't 
it be brought in sync, perhaps by using the modern DRY way:
///
unittest {...}
Or will that necessarily precede the unittest with "Example:"?

At any rate, I doubt the ~20 lines of introspection code - which 
sometimes gets outdated - should appear at all in hasSlicing et 
al. documentation.  If a developer encounters problems with 
hasSlicing and needs the source, a link to the up-to-date source 
itself may be enough.

> I don't know whether this is intentional. I'd say we should 
> allow a sliceable range to have slices of a different type.
>
> EDIT:
> The documentation even says that it's intentional, but gives no 
> justification.

I don't know why the type should be the same, but that may well 
be needed.

Anyway, after more digging, I found out I only need to implement 
save() to satisfy isRandomAccessRange, which makes sense when I 
think of it: the save() for arrays returns an array and not my 
struct.  And opSlice(...) to satisfy hasSlicing, which also makes 
sense if we accept that the slice needs to be the same type: a 
generic opSlice is not possible since operator overloads must be 
member functions, and even if it were, it would not know how to 
construct an object of our specific type in the general case.  
So, that's some boilerplate, but its appearance seems justified.

Here's the working code I got:
-----
import std.algorithm, std.random, std.range, std.stdio;
struct S {
     int[] contents;
     alias contents this;
     @property auto save() {return S(contents.dup);}
     auto opSlice(size_t lo, size_t hi) {return 
S(contents[lo..hi]);}
}
void main() {
     S s;
     s = [4, 3, 2, 1];
     writeln(s[1..3]); // [3, 2]
     writeln(isInputRange!(S)); // true
     writeln(isForwardRange!(S)); // true
     writeln(isBidirectionalRange!(S)); // true
     writeln(isRandomAccessRange!(S)); // true
     writeln(hasSlicing!(S)); // true
     auto t = s;
     sort(s);
     writeln(s); // [1, 2, 3, 4]
     randomShuffle(s);
     writeln(s); // random permutation
     writeln(t); // same as above
}
-----

Now, if I remove the custom opSlice and alter the checks in 
hasSlicing as you suggested, I get the error:
-----
sorting.d(1160): Error: quickSortImpl (S r, uint depth) is not 
callable using argument types (int[], uint)
-----
Which means quickSortImpl (S r, uint depth) can't instantiate and 
call quickSortImpl (int[] r, uint depth) for recursively sorting 
its slices.  That is understandable.


More information about the Digitalmars-d-learn mailing list