On Thursday, July 15, 2010 17:40:26 Gareth Charnock wrote: > So having got a collectors' edition TDPL, I though I'd have a try at > writing some concurrent code. The idea was a worker thread(s) would do > some work and write the results to some immutable objects. These would > get passed to an indexer thread that would do neat stuff like indexing > the references to the objects in things like hash tables and such, > performing any reduce type operations along the way. These views would > then be passed back to workers in due course. Unfortunately I hit a > snag. It appears you can't do this: > > class A { > ... > } > immutable A a1 = new immutable(A); //pointer to a real, immutable object > immutable A a2; //pointer to null > a2 = a1; //error, guess I doomed a2 to a life of being useless > > I thought that as such assignments don't change the underlying objects > in memory, they would be fine. Compare to: > > immutable(char)[] s1 = "hello world"; //fat pointer to a section of > immutable memory > immutable(char)[] s2; //fat pointer to null > s2 = s1; //fine > > The only solutions I can think of: > 1) Use a pointer to a class. Works, but that just seems very unsafe and > just plain un-D-ish. We also have to dereference two pointers. > 2) Work entirely with immutable(A)[], which is not quite as crazy as it > seems as we are copying about arrays of pointers rather than arrays of > A. It's still quite crazy. > 3) Write some sort of wrapper struct to hide the pointer. > 4) Perhaps ref works like C++ int&? > ref immutable(A) ref_a //error > Nope. > > So is this intended behavior? Am I missing something obvious?
First off, you're using using a reference, not a pointer. They're similar but quite different. If you were using a pointer, you could do immutable (A)* a1; and the object would be immutable while the pointer would be mutable. It's a mutable pointer to an immutable object of type A. The problem with a reference is that it has no syntactic way to differentiate between what's doing the refering and what's being referred. Because immutable is transitive, immutable A a1; is an immutable reference to an immutable object of type A. As soon as you try and make a reference immutable, what it refers to is immutable as well. There is no syntactic way to fix the problem. The solution is Rebindable!(T) in std.typecons. Rebindable!(T) is a wrapper struct. It allows you to have const and immutable references and still change what they refer to. Take this example from the docs: // Rebindable references to const and immutable objects void bar() { const w1 = new Widget, w2 = new Widget; w1.foo(); // w1 = w2 would not work; can't rebind const object auto r = Rebindable!(const Widget)(w1); // invoke method as if r were a Widget object r.foo(); // rebind r to refer to another object r = w2; } By wrapping the const (or immutable) Widget, you can "rebind" what is "bound" by Rebindable!(T) and effectively get a mutable reference to a const or immutable object. It's not terribly pretty, but apparently no one could come up with a satistfactory way of doing it in the language itself given the syntax for references. So, Rebindable!(T) is the solution. - Jonathan M Davis