Array type conversion

janderson askme at me.com
Sat Apr 28 15:25:10 PDT 2007


Mark Burnett wrote:
> I have spent much of the last couple of weeks trying to choose a language in which to write the code for my PhD thesis (in computational physics).  I had very nearly decided on using c++, when yesterday I stumbled upon D.  So far I'm ecstatic about it's feature set.
> 
> Still there are one or two things that strike me as odd:  in particular that arrays of a derived type can be converted to an array of a base type.  As pointed out by Marshall Cline, [http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.4] this is dangerous.  Is this possibly a holdover from c++?  It is explicitly mentioned in the array page that they behave this way, so I am not convinced that is the case.
> 
> Fortunately not all of the problems associated with doing this in c++ exist in d (see attached code).  What d seems to do is treat all derived[] as base[], which is silly because if i want a base[], I would just declare it that way.  Asking for a derived[] is how I say that I  *only* want derived objects in there.
> 
> The attached code generates this output using gdc 0.23 on OSX:
> Here are the different apples we have:
> A P P L E -- Red
> A P P L E -- Red
> A P P L E -- Red
> Orange -- Orange
> A P P L E -- Red
> 
> Please, keep in mind that this test is the first d I have written, and I don't claim to understand the language.  Array type promotion just seems odd to include, and I would like to understand the motivation for doing so.


Ok looking at your example again:  I think the real issue is this:
// Code to test array type promotion.

import std.stdio;

class Fruit
{
	enum color { Red, Orange, Fuchsia };
	static char[] [color] colorlist;

	color mycolor;
	char [] name;

	static this() // Love these :)
	{
		colorlist[color.Red] = "Red";
		colorlist[color.Orange] = "Orange";
		colorlist[color.Fuchsia] = "Fuchsia";
	}

	this()
	{
		mycolor = color.Fuchsia;
		name = "Generic Fruit";
	}

	void whatkind()
	{
		writefln("%s -- %s", name, colorlist[mycolor]);
	}
}

class Apple : Fruit
{
	this()
	{
		mycolor = color.Red;
		name = "A P P L E";
    	}


	void DropApple()
	{
		writefln("DropApple");
	}
}

class Orange : Fruit
{
	struct orangesarebiggerthanapples
	{
		int numberofbumps = 42;
		double ph = 5.3;
	}
	this()
	{
		mycolor = color.Orange;
		name = "Orange";
	}

	void EatOrange()
	{
		writefln("EatOrange");
	}
}


void addfavoritefruit(Fruit [] basket, int index)
{
	basket[index] = new Orange;
}


void main(char [] [] args)
{
	Apple [] lotsofapples;
	Fruit [] justsomefruits;

	lotsofapples.length = 5;
	lotsofapples[0] = new Apple;
	lotsofapples[1] = new Apple;
	lotsofapples[2] = new Apple;

	justsomefruits = lotsofapples; // Dangerous!

	justsomefruits.addfavoritefruit(3);
	
	lotsofapples[4] = new Apple;

	writefln("Here are the different apples we have:");
	foreach (apple; lotsofapples)
	{
		apple.DropApple();
	}

	while(true) {}
}

DropApple
DropApple
DropApple
EatOrange  //What the hell, I never called this function.
DropApple


//2

//Even worse, remove the EatOrange

DropApple
DropApple
DropApple
Error: Access Violation


The problem is the refcopy.  I'm not sure this sort of conversion should 
be band.  However I'm not sure what the correct type of checking should 
be used.  Maybe it should only be converted when passed into the 
function (otherwise require a .ptr qualifier).  It would still have 
potential issues but I think it would be less error prone.

-Joel



More information about the Digitalmars-d mailing list