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