From slices to perfect imitators: opByValue

Sönke Ludwig via Digitalmars-d digitalmars-d at puremagic.com
Thu May 8 08:39:25 PDT 2014


Am 08.05.2014 16:22, schrieb Jonathan M Davis via Digitalmars-d:
> 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
>

Unless I'm completely mistaken, it's safe to cast away const when it is 
known that the original reference was constructed as mutable. Anyway, 
this is what I do in my own RefCount struct. But my main point was that 
any user defined reference type is affected by the head vs. tail const 
issue, not just range types. So a decent solution should solve it for 
all of those types.

BTW, since RefCount would usually do manual memory management, it can't 
be used in pure contexts anyway. Proper support of scope/lent pointers 
would solve that, though. Ideally, there would be a way to allow a 
RefCount!T to implicitly cast to T if passed as a scoped parameter.


More information about the Digitalmars-d mailing list