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