<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 21 June 2015 at 09:31, Edmund Smith via Digitalmars-d <span dir="ltr"><<a href="mailto:digitalmars-d@puremagic.com" target="_blank">digitalmars-d@puremagic.com</a>></span> wrote:<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">First post, so let's see how this goes:<span class=""><br>
<br>
On Saturday, 20 June 2015 at 00:07:12 UTC, Andrei Alexandrescu wrote:<br>
</span><span class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
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.<br>
<br>
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.<br>
</blockquote>
<br></span>
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 (<a href="http://dlang.org/const3.html" rel="noreferrer" target="_blank">dlang.org/const3.html</a>) 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.<br>
<br>
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).<br>
<br>
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?).<br>
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.<br>
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.<br>
<br>
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.<br>
<br>
'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.<br>
<br></blockquote><div><br></div><div>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: <a href="http://forum.dlang.org/thread/xhlbenngkdpueqnhdqkg@forum.dlang.org?page=1">http://forum.dlang.org/thread/xhlbenngkdpueqnhdqkg@forum.dlang.org?page=1</a><br></div></div></div></div>