We need a typesystem-sanctioned way to cast qualifiers away

Iain Buclaw via Digitalmars-d digitalmars-d at puremagic.com
Sun Jun 21 02:32:53 PDT 2015


On 21 June 2015 at 09:31, Edmund Smith via Digitalmars-d <
digitalmars-d at puremagic.com> wrote:

First post, so let's see how this goes:
>
> On Saturday, 20 June 2015 at 00:07:12 UTC, Andrei Alexandrescu wrote:
>
>> 1. Reference counting: it's mutation underneath an immutable appearance.
>> For a good while I'd been uncomfortable about that, until I figured that
>> this is the "systems" part of D. Other languages do use reference counting,
>> but at the compiler level which allows cheating the type system. It is
>> somewhat fresh to attempt a principled implementation of both reference
>> counting and safe functional collections, simultaneously and at library
>> level.
>>
>> My conclusion is that changing the reference count in an otherwise
>> immutable structure is an entirely reasonable thing to want do. We need a
>> way to explain the type system "even though the payload is const or
>> immutable, I'll change this particular uint so please don't do any
>> optimizations that would invalidate the cast". The user is responsible for
>> e.g. atomic reference counting in immutable data etc.
>>
>
> This idea makes sense with the type checker, although I'm not sure how it
> fits D's current memory model. On the page detailing const and immutable (
> dlang.org/const3.html) it mentions that immutable data 'can be placed in
> ROM (Read Only Memory) or in memory pages marked by the hardware as read
> only', which may be problematic if an immutable's mutable reference counter
> is placed in a read-only page. Would this potentially be changed? It
> suggests that the compiler needs a way of telling if the struct is a
> typical immutable struct or is privately-mutable, publicly-immutable.
>
> As for the language level, it helps to look at how an immutable value
> propagates. It can be passed by value or by reference, passed between
> threads without issue and its value never changes. The thread safety
> strongly implies that what isn't immutable is shared, so that every field
> in an immutable struct is still thread-safe. Its exposed value never
> changing is also crucial IMO, to the point where I think it should be a
> compiler error if the 'facade' of immutability collapses (e.g. mutable data
> is public or modifies a public function's result).
>
> Passing copies also raises a point about the current state of 'immutable
> struct S', which has a few things different to normal structs (and block
> anything but POD types. Is this intentional?).
> Currently, D lacks destructors and postblit constructors on immutable
> structs, giving the error 'Error: immutable method SomeStruct.__postblit is
> not callable using a mutable object'. Throwing an immutable qualifier makes
> it no longer recognisable as a postblit constructor, so that doesn't work
> either. This makes perfect sense under the current assumption that
> 'immutable struct' implies it is a POD struct, but if/when under-the-bonnet
> mutability goes ahead, this assumption will no longer hold (and postblit
> constructors are pretty useful with refcounting). The same goes for
> destructors, too. Without these, passing immutable refcounts by copy isn't
> safe - the copy keeps the pointer, but doesn't increase the counter. This
> leads to a potential use-after-free if the copy outlives every 'proper'
> reference.
> I'm not sure whether this is all necessary, however - it is possible to
> just ignore 'immutable struct' and use 'alias MyStruct =
> immutable(MyActualStruct);', in which case the previous paragraph can be
> ignored.
>
> After playing around with examples of how to do proper immutable reference
> counting (e.g. static opCall factory) I think the smallest change large
> enough to work with would be to allow transitive immutability to not
> transfer immutability to 'private shared' variables (or behave this way in
> the memory model, so that casting to mutable is safe but the type system
> remains entirely transitive), while simultaneously making it a compile-time
> error to read or write to these variables from exposed (public) functions.
> This may want to be loosened or have exceptions (debug builds etc.),
> depending on other use-cases.
>
> 'shared' seems to be used at the moment for a few different hacks (e.g.
> GDC having 'shared' and 'volatile' behave identically for a while) and
> nothing particularly concrete, save some library functions and inter-thread
> message passing. It also seems suitable for avoiding overeager compiler
> optimisations, since the 'shared' qualifier already shows that typical
> assumptions can't be made about it. Also, most existing scenarios I can
> think of for a private shared variable in an immutable object are rather
> contrived. Finally, it should push the use of atomic code, or at least
> basic multithreading good practices.
>
>
Shared was not well documented (nor were there any strong library support)
when it was initially conceived.  It's purpose has become clearer with use:
http://forum.dlang.org/thread/xhlbenngkdpueqnhdqkg@forum.dlang.org?page=1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20150621/6768ced7/attachment-0001.html>


More information about the Digitalmars-d mailing list