On Wednesday, 31 October 2012 at 08:58:18 UTC, Jonathan M Davis
wrote:
I agree, but for that to be realistic, I think that issue# 7177
needs to be
implemented first. You should check out the pull request that I
have for
improving hasSlicing. I just updated it according to some of
the discussion
here, and it now checks the behavior of opDollar when it works
with the range
being sliced. For finite ranges, it essentially enforces that
they function
like arrays do, and for infinite ranges, it comes as close to
that as it can:
https://github.com/D-Programming-Language/phobos/pull/854
As of the latest state of that pull request, hasSlicing looks
like
template hasSlicing(R)
{
enum bool hasSlicing = !isNarrowString!R && is(typeof(
(inout int _dummy=0)
{
R r = void;
static if(isInfinite!R)
typeof(take(r, 1)) s = r[1 .. 2];
else
R s = r[1 .. 2];
s = r[1 .. 2];
static if(is(typeof(r[0 .. $])))
{
R t = r[0 .. $];
t = r[0 .. $];
static if(!isInfinite!R)
{
R u = r[0 .. $ - 1];
u = r[0 .. $ - 1];
}
}
static assert(isForwardRange!(typeof(r[1 .. 2])));
static assert(hasLength!(typeof(r[1 .. 2])));
}));
}
- Jonathn M Davis
I'm not a huge fan of the "opDollar" check, because essentially,
it doesn't really buy you anything: if hasSlicing!R, then is "r =
r[1..$]" legal? Who knows! You as a developer need to check
manually that "r[0 .. $]" is legal first anyways...
Under those circumstances, why not cleanly splice the two notions?
//----
template hasSlicing(R)
{
enum bool hasSlicing = !isNarrowString!R && is(typeof(
(inout int _dummy=0)
{
R r = void;
static if(isInfinite!R)
typeof(take(r, 1)) s = r[1 .. 2];
else
R s = r[1 .. 2];
s = r[1 .. 2];
static assert(isForwardRange!(typeof(r[1 .. 2])));
static assert(hasLength!(typeof(r[1 .. 2])));
}));
}
template hasSlicingToEnd(R)
{
enum bool hasSlicingToEnd = !isNarrowString!R && is(typeof(
(inout int _dummy=0)
{
R r = void;
static if(is(typeof(r[0 .. $])))
{
R t = r[0 .. $];
t = r[0 .. $];
static if(!isInfinite!R)
{
R u = r[0 .. $ - 1];
u = r[0 .. $ - 1];
}
}
}));
}
//----
IMO, this makes a clean distinction between both "types" of
slicing. An added bonus is that (for now) it also correctly
supports finite RA ranges that don't define opDollar.
//----
PS: Do we really have to force that infinite slice to be of a
type of "take"? Does that mean we can't imagine an infinite range
that defines it's own finite slice type?
if we change the code to:
//----
static if(isInfinite!R)
auto s = r[1 .. 2]; //HERE1
else
R s = r[1 .. 2];
s = r[1 .. 2]; //HERE2
//----
Then we force nothing on the slice's type (HERE1), but do verify
that subsequent slices will be assignable back to the original
slice (HERE2)...