4

In an object, I have an array of const-handles to some object of another specific class. In a method, I may want to return one of this handles as an inout-parameter. Here as a simplified example:

class A {}

class B {
    const(A) a[];
    this() { 
        a = [new A(), new A(), new A()];
    }

    void assign_const(const(A)* value) const {
        // *value = a[0]; // fails with: Error: cannot modify const expression *value
    }
}
void main() {
    const(A) a;
    B b = new B();
    b.assign_const(&a);
    assert(a == b.a[0]); // fails .. obviously
}

I do not want to remove the const in the original array. Class B is meant as some kind of view onto a collection constant A-items. I'm new to D coming from C++. Do I have messed up with const-correctness in the D-way? I've tried several ways to get this to work but have no clue how to get it right.

How is the correct way to perform this lookup without "evil" casting?

Peter Schneider
  • 1,683
  • 12
  • 31

1 Answers1

5

Casting away const and modifying an element is undefined behavior in D. Don't do it. Once something is const, it's const. If the element of an array is const, then it can't be changed. So, if you have const(A)[], then you can append elements to the array (since it's the elements that are const, not the array itself), but you can't alter any of the elements in the array. It's the same with immutable. For instance, string is an alias for immutable(char)[], which is why you can append to a string, but you can't alter any of its elements.

If you want an array of const objects where you can alter the elements in the array, you need another level of indirection. In the case of structs, you could use a pointer:

const(S)*[] arr;

but that won't work with classes, because if C is a class, then C* points to a reference to a class object, not to the object itself. For classes, you need to do

Rebindable!(const C) arr;

Rebindable is in std.typecons.

Jonathan M Davis
  • 37,181
  • 17
  • 72
  • 102
  • Casting away const were my last option even if it were defined behaviour. Before this, I had removed the const altogether. But it would have been ages, before I had found an acceptable solution with `Rebindable` (.. or at least days). Thank you! – Peter Schneider Feb 13 '13 at 19:05
  • 1
    It's the sort of thing you're probably only going to know about if you read an article which mentions it or an answer to a question like this. But due to how D's type system works, you pretty much have to have something like `Rebindable` to make a class `const` but not have its reference be `const` - the type system simply doesn't have any concept of the difference between the two. `Rebindable` solves the problem well enough, but since most people have trouble understanding why they can't do it in the language itself, it's not the sort of thing that most people will think of. – Jonathan M Davis Feb 13 '13 at 23:45