Kinds of containers
Jonathan M Davis via Digitalmars-d
digitalmars-d at puremagic.com
Sun Oct 25 14:59:34 PDT 2015
On Sunday, 25 October 2015 at 15:42:02 UTC, Andrei Alexandrescu
wrote:
> Jonathan, do you have a link to your work?
Sorry, but no. I haven't mucked around with this issue recently,
and whatever I have left on the topic is either buried in a
newsgroup post somewhere or buried on my hard drive somewhere
where I wouldn't know where to find it. Searching on the
newsgroup for discussions on tail-const would find stuff related
to this if you want to go spelunking, since it's the tail-const
issues where the fact that const(Foo!T) and Foo!(const T) aren't
related typically comes up and likely causes the largest problems.
The EMSI containers may have some interesting stuff with regards
to the problem, since I know that those guys tried very hard to
be able to support tail-const ranges.
The main thing that I recall is that if you want to be able to
get a tail-const range from a const range, you have to use a
static if to protect the const opSlice declaration so that you
don't end up with a recursive template instantiation (since it
has to return another instantiation of the range's template). And
even then, an opSlice with no arguments isn't technically a
standard range function, because none of the range traits require
it (so you can't rely on a range having it). Rather, it's a
container function for getting a range. And even if it were a
range function, it wouldn't get the special treatment that arrays
get when being passed to a templated function (IFTI infers an
array's type as being a tail-const slice, which doesn't happen
with anything else), and even if it did, a const range wouldn't
implicitly convert to its tail-const variant without an alias
this, which is likely to create a whole other set of problems -
particularly since implicit conversions tend to wreak havoc in
generic code.
Handling tail-const with ranges in a manner consistent with
arrays and supporting $ with ranges are probably the two big
places that ranges can't currently emulate the behavior of
arrays. The $ problem is technically solvable as-is, but without
some form of https://issues.dlang.org/show_bug.cgi?id=7177 being
implemented, changing hasSlicing or isRandomAccessRange to
require that a range works with $ would likely break too much
code, so no range-based code can really using $ unless it
explicitly checks for it. However, I'm not sure that the
tail-const problems is solvable without further language
improvements. We likely need some sort of standard way to convert
a const(Foo!T) to a Foo!(const T) - possibly via opSlice, since
it wouldn't make sense for something that wasn't emulating an
array. And we might need to make changes to IFTI so that it
infers tail-const for ranges (at least if they provide such a
conversion), but I'm not sure what the implications of that are.
There's also the issue of accidentally slicing ranges (e.g.
https://issues.dlang.org/show_bug.cgi?id=14619 ) which can cause
incorrect behavior in at least some cases, depending on the range
type - and if a range is a reference type, then slicing it would
be akin to saving it, which could mean allocating. So, unlike
with arrays, we probably don't want ranges in general to get
sliced just because they're passed to a function, meaning that we
may just want IFTI to not play fun games with ranges and let
arrays be special there.
In any case, I should probably try and find time soon to sit down
and at least go over the issues in detail again so that I'm
clearer on them and could possibly present a DIP intended to
resolve them. I haven't dug through them recently, and my general
approach up until now when I've needed to actually get work done
has been to just not use const or inout with ranges.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list