Making array elements truly const/immutable

Jonathan M Davis jmdavisProg at gmx.com
Thu Aug 2 09:39:03 PDT 2012


On Thursday, August 02, 2012 09:55:51 Joseph Rushton Wakeling wrote:
> Hello all,
> 
> While playing around I noticed something that rather disturbed me about
> const/immutable's relationship with arrays. If I do e.g.
> 
> import std.stdio;
> 
> void main()
> {
> immutable(int)[] foo = [1, 2, 3, 4, 5];
> 
> int[] bar = cast(int[]) foo;
> 
> bar[2] *= 2;
> 
> foreach(b; bar)
> writeln(b);
> writeln();
> 
> foreach(f; foo)
> writeln(f);
> }
> 
> ... then the tweak to bar will also affect foo.
> 
> Now, it seems fairly evident why this is -- I'm taking something that is
> effectively a pointer to (immutable int) and casting it to a pointer to int,
> and so of course the latter can mutate the data contained. I can even see
> potential applications for this kind of cast.
> 
> But, 2 questions: (i) is there a way to mark an array as "under no
> circumstances allow anything to modify the contents" in a way that _can't_
> be cast away like this? and (ii) given that I can use instead bar = foo.dup
> to copy foo, is this guaranteed to produce a _copy_ or is it smart inasmuch
> as the compiler will check if bar is actually mutated and so only create a
> duplicate if needed?
> 
> The motivation is that I want to have a class which contains a dynamic array
> as a private member variable, but which is readable through a class
> property. i.e. something like
> 
> class Foo
> {
> private int[] _foo;
> @property immutable(int)[] foo { return _foo; }
> }
> 
> ... but where it's guaranteed that no external agent can touch the inside of
> _foo. So, yes, I could return _foo.idup, but I'd like to be able to
> guarantee that extra arrays won't be allocated unless strictly necessary.

const and immutable are the type system's protection against mutation. Casting 
them away removes that protection. D is a systems language and will let you do 
stuff like that. The only way to protect the underlying bytes is for them to be 
in ROM, because once you sidestep the type system, the language can't protect 
you anymore. Now, casting away const or immutable and mutating a variable is 
undefined behavior, so doing it is a really bad idea, but once the const or 
immutable is gone from the type, there's nothing that the type system can do 
to protect you, because you explicitly threw away its protection.

Anyone casting away immutable on the array you're returning from foo, is 
throwing away the type system's guarantees, and if they then mutate the 
variable, they're doing something that is undefined. So, if it blows up in 
their face, it's their fault. They're doing something stupid. There's no need 
for you to worry about protecting against it.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list