On Thu, 08 May 2014 14:48:18 +0200 Sönke Ludwig via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> Am 08.05.2014 13:05, schrieb monarch_dodra: > > On Thursday, 8 May 2014 at 07:09:24 UTC, Sönke Ludwig wrote: > >> Just a general note: This is not only interesting for range/slice > >> types, but for any user defined reference type (e.g. RefCounted!T > >> or Isolated!T). > > > > Not necessarily: As soon as indirections come into play, you are > > basically screwed, since const is "turtles all the way down". > > > > So for example, the conversion from "const RefCounted!T" to > > "RefCounted!(const T)" is simply not possible, because it strips the > > const-ness of the ref count. > > > > What we would *really* need here is NOT: > > "const RefCounted!T" => "RefCounted!(const T)" > > But rather > > "RefCounted!T" => "RefCounted!(const T)" > > > > The idea is to cut out the "head const" directly. This also applies > > to most ranges too BTW. > > > > We'd be much better of if we never used `const MyRange!T` to begin > > with, but simply had a conversion from `MyRange!T` to > > `MyRange!(const T)`, which references the same data. > > > > In fact, I'm wondering if this might not be a more interesting > > direction to explore. > > The reference count _must_ be handled separate from the payload's > const-ness, or a const(RefCount!T) would be completely dysfunctional. Unless the reference count is completely separate from const(RefCount!T) (which would mean that the functions which accessed the reference couldn't pure - otherwise they couldn't access the reference count), const(RefCount!T) _is_ completely dysfunctional. The fact that D's const can't be cast away in to do mutation without violating the type system means that pretty much anything involving references or pointers is dysfunctional with const if you ever need to mutate any of it (e.g. for a mutex or a reference count). std.typecons.RefCounted is completely broken if you make it const, and I would expect that of pretty much any wrapper object intended to do reference counting. Being able to do RefCounted!T -> RefCounted!(const T) makes some sense, but const(RefCounted!T) pretty much never makes sense. That being said, unlike monarch_dodra, I think that it's critical that we find a way to do the equivalent of const(T[]) -> const(T)[] with ranges - i.e. const(Range!T) or const(Range!(const T)) -> Range!(const T). I don't think that Range!T -> Range!(const T) will be enough at all. It's not necessarily the case that const(Range!T) -> Range!(const T) would always work, but it's definitely the case that it would work if the underlying data was in an array, and given what it takes for a forward range to work, it might even be the case that a forward range could do be made to do that conversion by definition. The problem is the actual mechanism of converting const(Range!T) to Range!(const T) in the first place (due to recursive template instantiations and the fact that the compiler doesn't understand that they're related). The concept itself is perfectly sound in many cases - unlike with const(RefCounted!T) - because in most cases, with a range, it's the data being referred to which needs to stay const, whereas the bookkeeping stuff for it can be copied and thus be made mutable. With a reference count, however, you have to mutate what's actually being pointed to rather than being able to make a copy and mutate that. So, const(RefCounted!T) -> RefCounted!(const T) will never work - not unless the reference is outside of const(RefCounted!T), in which case, it can't be pure, which can be just as bad as not working with const. - Jonathan M Davis