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)...

Reply via email to