5

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.

Meta
  • 1,091
  • 6
  • 14

1 Answers1

5

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[].

Mihails Strasuns
  • 3,783
  • 1
  • 18
  • 21
  • Thank you, that clears it up. However, the Take struct defines an opIndex, yet when I try `writeln(a[0]);`, it doesn't work. What is the reason for this? – Meta Oct 22 '12 at 21:52
  • 1
    It defines opIndex only for RandomAccessRange, which narrow strings are not. This rationale I can't understand, to be honest, as narrow strings actually _are_ usable as a random access code point range via native slicing. This a good question. – Mihails Strasuns Oct 23 '12 at 11:29
  • 1
    P.S. I recommend using d tag or both d and d2, as there are a lot more people subscribed to d feed. – Mihails Strasuns Oct 23 '12 at 11:30
  • 1
    @Михаил Страшун All strings are treated explicitly as ranges of dchar, because it generally makes no sense to operate on a range of code units, whereas slicing narrow strings operates on chars or wchars, not dchars, so slicing couldn't work unless you knew that you were working explicitly on strings, and even then, it often can't be done in O(1), because you need to find the indices of valid code points first. This answer http://stackoverflow.com/a/12289147/160887 and this answer http://stackoverflow.com/a/6401889/160887 both discuss the issue. Feel free to post a new question if you need to. – Jonathan M Davis Oct 24 '12 at 10:45
  • @JonathanMDavis Yes, I am aware of reasoning, but problem is there actually are some cases when strings are treated as code point ranges and I had a hard time building a consistent design pciture :) ( I have already started a related thread in D.learn ) – Mihails Strasuns Oct 24 '12 at 10:53