From slices to perfect imitators: opByValue

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Thu May 8 07:22:14 PDT 2014


On Thu, 08 May 2014 14:48:18 +0200
Sönke Ludwig via Digitalmars-d <digitalmars-d at 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



More information about the Digitalmars-d mailing list