Search code examples
dphobos

Cannot Slice Take!R from std.range in D?


I'm trying to use the slice operator to obtain a slice of the return value of the take function from std.range. My code:

auto tempChunk = ['a', 'b', 'c', 'd'];
auto a = tempChunk.take(3);
writeln(a[0..2]);

As Take!R in this case is just an alias for char[], I'd expect this to compile. However, the compiler tells me that Take!(char[]) cannot be sliced with []. Taking another example:

int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 
auto s = arr.take(5);
writeln(s[0..4]);

This will compile and run without a problem, printing [1, 2, 3, 4, 5]. I am completely confused at this point as to why the first example won't work, while the second does.


Solution

  • take template uses hasSlicing to determine if slice of input can be returned instead of Take!R struct. Checking actual return types makes it a bit more clear:

    import std.range, std.stdio;
    
    void main()
    {
        auto chararr = ['a', 'b', 'c', 'd'];
        auto a = chararr.take(3);
        writeln( typeid(typeof(a)) );
    
        auto intarr = [ 1, 2, 3, 4 ];  
        auto b = intarr.take(3);
        writeln( typeid(typeof(b)) );
    }
    
    // Output:
    // std.range.Take!(char[]).Take
    // int[]
    

    hasSlicing is explicitly instructed to return false for all "narrow strings" - those, which element may not represent single character, but a code point (char and wchar based ones).

    Now, here is where my speculations start but I suppose it is done to prevent accidental creating of malformed UTF-8 & Co strings using slicing. Better to use dchar[] if you do not have any real need in char[].