Overzealous immutable and classes

Jonathan M Davis jmdavisprog at gmail.com
Thu Jul 15 18:08:14 PDT 2010


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


More information about the Digitalmars-d-learn mailing list