std.concurrency & immutable classes...
Tomek Sowiński
just at ask.me
Fri Feb 11 14:08:26 PST 2011
Steven Schveighoffer napisał:
> > It would be much easier if he provided the specific case(s) which broke
> > his teeth. Then we'll all know where's the problem. If it's soluble,
> > it'll open the door to tail type modifiers in general, not just in
> > classes. It's a burning issue e.g. with ranges (mostly struct).
> >
> > http://d.puremagic.com/issues/show_bug.cgi?id=5377
> >
> > Look at the attachment to get a feel of what hoops we'll have to jump
> > through to side-step lack of tail X.
>
> I've worked through this very same problem (a few months back), thinking
> that we need a general solution to tail-const. The large issue with
> tail-const for structs in the general case is that you cannot control the
> type of 'this'. It's always ref. This might seem like a very
> inconsequential detail, but I realized that a ref to X does not implicitly
> convert to a ref to a tail-const X. This violates a rule of two
> indirections, in which case you are not able to implicitly convert the
> indirect type, even if the indirect type would implicitly convert outside
> the reference.
>
> A simple example, you cannot convert an int** to a const(int)**. Reason
> being, then you could change the indirect pointer to point to something
> that's immutable, and the original int ** now points to immutable data.
I tried to understand this on an example and now I'm even more confused. :)
int* p;
int** pp = &p;
const(int)** cpp = pp; // compiles fine
immutable int i = 7;
*cpp = &i;
**pp = 5; // mutate the immutable
writeln(cpp, ' ', pp);
writeln(*cpp, ' ', *pp, ' ', &i);
writeln(**cpp, ' ', **pp, ' ', i);
The output is interesting:
12FE08 12FE08
12FE14 12FE14 12FE14
5 5 7
So even they all point to i at the end, it remains unchanged. What gives? Register caching? It doesn't matter as the int** to a const(int)** conversion should fail in the first place, but I'm curious...
> The same is for tail-const structs, because you go through one ref via
> 'this' and the other ref via the referring member.
>
> What does this all mean? It basically means that you have to define
> *separate* functions for tail-const and const, and separate functions for
> tail-immutable and immutable. This is untenable.
I, from the very first discussions, assumed tail-const functions are inevitable. You define empty() as const but popFront() as tail-const. Feels natural.
> You might ask "why doesn't this problem occur with tail-const arrays?",
> well because you *don't pass them by ref*. With structs we have no choice.
>
> I think what we need is a way to define two different structs as being the
> tail-const version of the other, with some compiler help, and then we do
> not need to define a new flavor of const functions. We still need to
> define these "tail-const" functions, but it comes in a more understandable
> form. But importantly, the implicit cast makes a *temporary* copy of the
> struct, allowing the cast to work.
I'd like to understand it better. How would you define with this scheme, say, a range on a const collection, to which ranges on an (im)mutable collection are implicitly convertible?
--
Tomek
More information about the Digitalmars-d-learn
mailing list