On Thursday, 22 October 2015 at 15:53:21 UTC, Jonathan M Davis wrote:
On Thursday, 22 October 2015 at 15:26:30 UTC, bitwise wrote:
On Thursday, 22 October 2015 at 05:09:38 UTC, deadalnix wrote:
The elephant in the room: make the template parameter's type qualifier transitive with the collection's qualifier.

Not sure exactly what you mean by this. Currently, Ranges and Cursors are templated on the type of the container, so If the container is const, you get a const Range or Cursor. I haven't gone over the containers with a fine tooth comb yet, so if you can point anything out, it would be helpful.

LOL. const and ranges do _not_ mix well - in part because popFront inherently requires that the range be mutable - but mostly because of templates.

If you have const(T)[], and you then you slap another const on it - const(const(T)[]) - the compiler knows full-well that that's equivalent to const(T[]). In fact, it even knows that if you slice a const(T[]), it's perfectly safe for the result to be const(T)[], because it's a different array, and by keeping the elements const, it won't screw with the elements of the one it was sliced from (since they're the same elements). But what about with ranges?

If you have Range!(const T) and then you do const Range!(const T), is that equivalent to const(Range!T)? Maybe, maybe not. The compiler certainly doesn't treat it as such - and it can't. Similarly, if you have const(Range!T) or const(Range!(const T)), and you slice the range, the compiler doesn't magically know that the slice can be Range!(const T). As far as the compiler is concerned, we're dealing with different types here. After all, what if the Range type had something like this in it

struct Range(T)
{
    static if(is(T == const))
    {
        // do something differently here
    }
}

The entire guts of Range could be completely different simply due to a difference in constness. Template constraints could also be used to overload on constness. So, unlike with arrays, there really is no guarantee that two instantiations of the same template are at all related to one another even when they seem to only differ by constness. Heck, to even attempt to have a range type which has an opSlice which returns a tail-const slice _requires_ that you have static ifs checking for constness, or you end up with a recursive template instantiation.

So, even without getting containers involved, const and ranges do _not_ mix well, even though const and arrays get along fantastically. And when you have to start considering what a containers opSlice is going to return an how it's going to deal with const, things get that much worse (e.g. is it even going to work to have opSlice be const). And depending on the container's internals, having a range only have const access to its underlying container could be problematic. IIRC, std.container.Array has had some issues with const related to its internals not having been designed in a way that worked well with D's const.

So, const throws a very interesting wrench into the mix when dealing with either ranges or containers, and the fact that const(Foo!T) is not necessarily the same as const(Foo!(const T)) can definitely be problematic.

- Jonathan M Davis

Maybe look at the code next time before you LOL......

     Bit

Reply via email to