array cast should be supported corrected

Robert Fraser fraserofthenight at gmail.com
Thu Aug 7 13:43:56 PDT 2008


Steven Schveighoffer Wrote:
> Actually, because of the way arrays work, this will cause a segfault only in 
> release mode, because a_array is still 0-length (and null).  Without release 
> mode, you get an array bounds exception
> 
> A better example would be:
> A[] a_array;
> a_array ~= new A;
> Base[] base_array = a_array;
> B b = new B;
> b.x = b.y = 100;
> base_array[0] = b;
> A a = a_array[0]; // a now points to b
> writefln(a.str); // Segfault!

Yes, you're right; my bad.

> > I don't have a D compiler on this computer so I can't test it out, but if
> > the compiler can implicitly cast A[] to Base[], then this is a hole in the 
> > type
> > system. The issue with interfaces is tangential.
> 
> The issues are orthogonal.  When casting to an interface array O(n) copying 
> is the only reasonable choice. 

We're saying the same thing ;-P. From wiktionary:
tangential = "Only indirectly related."
orthogonal = "Able to be treated separately."

> O(1) aliasing is OK for a base class if you 
> are not planning on changing the existing elements.

In this case it should require an explicit cast. A[] could be implicitly 
castable to const(Base[]) but not to const(Base)[] or Base[].

> > It's also extremely easy to overlook this error. Say you're passing an 
> > array
> > of A[] to a function that modifies an array of Base[] by possibly adding
> > things. In a large system, it can be a tricky bug to track down since the
> > error may not manifest itself until a while after it happens, and may not
> > always be a segfault (if they're the same size & it's just the bits being
> > interpreted as the wrong type, things could get very ugly -- it may not
> > always just segfault).
> 
> This is not a common case (to pass in a abstract base array in which you 
> plan on changing elements).  The common case is to use the base class array 
> as a means of writing a common function that *uses* the array, but does not 
> create elements in it.  For that, the cast is perfectly safe.  Or to use it 
> as a co-variant return value.  I think the benefits of being able to cast 
> this way outweigh the uncommon pitfalls.

I agree the advantages are enough to justify allowing aliasing without
serious subversion of the type system. But the cast _must be explicit_,
so users see a red flag there. It's potentially dangerous, since you
might accidentally interpret  one bit pattern as a different type. Short of
unions, only a cast can do that.

> I look at it no differently than doing:
> 
> class C {int x;}
> 
> C c;
> c.x = 5; // segfault

How is that at all the same? In the case of implicit base class casting,
you're tricking the compiler (likely without meaning to) into interpreting
the data as an incorrect type. In this case, the compiler is acting correctly
and you have a bug in your code.

> But the interface thing is a performance question.  Whether or not to 
> implicitly generate heap activity and run an O(n) algorithm by default is a 
> completely different question.

Agreed.



More information about the Digitalmars-d mailing list