Possible D2 solution to the upcasting array problem, and a related problem with const and nested arrays

Stewart Gordon smjg_1998 at yahoo.com
Fri Jan 2 04:51:46 PST 2009


I was just looking at this
http://d.puremagic.com/issues/show_bug.cgi?id=2544
which describes how it's possible to bypass const by doing this:

     const(int)[] answers = [42];
     int[][] unconsted = [[]];
     const(int)[][] unsafe = unconsted;
     unsafe[0] = answers;
     unconsted[0][0] = 43;

The problem is that converting from int[][] to const(int)[][] isn't 
safe, even though the language/compiler seems to think it is.

Really, it's another version of how you can use a DerivedClass[] as a 
BaseClass[] and thereby place in it an object that isn't of type 
DerivedClass.

There's actually a simple solution to this: specify that, where 
DerivedClass derives from BaseClass, DerivedClass[] cannot be implicitly 
converted to BaseClass[], but only to const(BaseClass)[].

Java has had something like this for a while, albeit not with arrays. 
That is, IIRC, you can assign a DataStructure<DerivedClass> to a 
variable of type DataStructure<? extends BaseClass> (or even 
DataStructure<? extends DerivedClass>) - this creates a read-only view 
of the data structure.  My proposal implements the same basic concept as 
this, but in a simpler way.  (Java also supports write-only 'views' with 
DataStructure<? super FurtherDerivedClass>, but I'm not sure we need 
anything like this in D at the moment.)

Now let's apply the same principle to the example in the bug report. 
Try defining that, in general, T[][] can be converted to const(T[])[] 
but not const(T)[][].  Then

     const(int)[] answers = [42];
     int[][] unconsted = [[]];
     const(int)[][] unsafe = unconsted;

would be illegal.  One would have to do

     const(int[])[] safe = unconsted;

and now

     safe[0] = answers;

is illegal.

In order to deal with the original, slightly more complex testcase, the 
principle needs to be applied in the same way to further levels of array 
nesting.  It would need applying to pointer types as well as array types 
- so, for example,

     int[]*[]

would be implicitly convertible to

     const(int[]*)[]

but not

     const(int[])*[]
     const(int)[]*[]

We could combine two applications of the principle, and get

     DerivedClass[][]

convertible to

     const(DerivedClass[])[]
     const(BaseClass[])[]

but not

     const(DerivedClass)[][]
     const(BaseClass)[][]
     BaseClass[][]


To summarise, the rules would be:

- Generalise the definition of an upcast to be any of the following:
-- conversion of a class type to a class type further up the hierarchy
-- conversion of a type to a const version of that type
-- a legal implicit conversion according to the following rule

- If U is an upcast of T, then a legal implicit conversion is from T[] 
to const(U)[], or T* to const(U)*.  In particular, conversion from T[] 
to U[] or T* to U* is illegal, except in the cases where T and const(T) 
are exactly the same.


If I've worked it out right, then these rules'll be fix the const system 
to be safe, while at the same time making upcasting of object arrays 
safe.  At least, before you consider invariant - a little more thought 
is needed to work out how this would be dealt with.

And it shouldn't break too much existing code.  Code that is already 
broken will just promote this breakage from runtime to compiletime, and 
those uses that were already 'correct' will be easily fixed by updating 
the declarations.  The unsafe conversions could be deprecated before 
being removed altogether, with messages such as

     conversion from int[][] to const(int)[][] is unsafe and deprecated, 
use const(int[])[] instead
     conversion from DerivedClass[] to BaseClass[] is unsafe and 
deprecated, use const(BaseClass)[] instead

These unsafe conversions could still be allowed by explicit casts, 
should they be needed for something, IWC you'd be expected to know what 
you're doing.

What does everyone think?  Even better, can anyone find any holes that 
my proposal misses?

Stewart.



More information about the Digitalmars-d mailing list