On 14-Nov-2015 02:10, Andrei Alexandrescu wrote:
I created a simple persistent list with reference counting and custom
allocation at http://dpaste.dzfl.pl/0981640c2835. It's a good
illustration of a number of issues. In particular, each cast must be
properly explained.
Here's my exegesis:
[snip]
* Lines 11-12: I came to terms with the notion that some types cannot be
made immutable. We've been trying to do reference counting on immutable
objects for a long time. It's time to acknowledge that true immutability
(which the immutable keyword models) and reference counting don't mix.
Const does work (more below). But overall I'm at peace with the notion
that if you can't live without immutable, I'll refer you to the garbage
collector.
* Lines 26-29: The allocator is fundamentally a mutable part of the
container. This is an insufficiency of our type system - we can't say
"this object may be constant, but this reference is to a mutable part of
it". We can't explain that necessity out of existence, and List is part
of the proof. So we need to make that cast legal.
Just don't make it const (see your point at 11-12). I have a feeling
that ref-count and allocator are in the same mold - fields that must mutate.
So I imagine const/immutable for complex types will only work like this:
struct Layout{
immutable Core core; //all constness ends here
// accounting fields
uint refCount;
UAllocator alloc;
// ... any tracing and/or stats fit this definition
}
I totally do not understand the whole knee-jerk reaction of "everything
must be const because it looks good in my code" and bug reports a-la:
const obj = SomeComplexTypeFromStd(....); // doesn't compile!
Well some types can't be transitively const (w/o sacrificing
functionality/performance). Low-level immutable is a tool to create
high-level immutable constructs IMHO.
It might make sense to re-purpose final storage class to be write-once
a-la Java, because this is what folks expect when writing
`immutable/const x = ...;` everywhere possible.
* Lines 141-152: I couldn't make tail() work with inout. Generally I'm
very unhappy about inout. I don't know how to use it. Everything I read
about it is extremely complicated compared to its power. I wish we
removed it from the language and replaced it with an understandable idiom.
I can't agree more. Every time dealing with inout when I finally think I
grok how it works the next instant I see that it doesn't do what I expect.
For me inout inevitably stops at the boundary of being unnable to have
List!(inout(T)) and the like.
--
Dmitry Olshansky