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

1

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.

Fortieth answered 22/10, 2012 at 15:47 Comment(0)
B
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[].

Beslobber answered 22/10, 2012 at 19:0 Comment(5)
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?Fortieth
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.Beslobber
P.S. I recommend using d tag or both d and d2, as there are a lot more people subscribed to d feed.Beslobber
@Михаил Страшун 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 https://mcmap.net/q/1458428/-std-algorithm-joiner-string-string-why-result-elements-are-dchar-and-not-char and this answer https://mcmap.net/q/1482705/-why-does-std-algorithm-fill-not-accept-character-arrays both discuss the issue. Feel free to post a new question if you need to.Loy
@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 )Beslobber

© 2022 - 2024 — McMap. All rights reserved.