Thread overview
Array initialization with common base - Best way?
Nov 09, 2008
deadimp
Nov 09, 2008
Jérôme M. Berger
Nov 09, 2008
deadimp
Nov 09, 2008
Ary Borenszweig
Nov 09, 2008
Bill Baxter
Nov 10, 2008
deadimp
Nov 10, 2008
Carl Clark
Nov 10, 2008
Ary Borenszweig
November 09, 2008
What's a 'good' way to initialize an array of references to classes using a common base? I've tried this and it works:

class Base
{
 void func();
}
class GoodChild : Base
{
 void func();
}
class BadChild : Base
{
 void func();
}
//...
auto list = [cast(Base)new GoodChild, new BadChild, ...];

I had tried doing it without the initial cast, but ran into issues because D (DMD v1.033) would infer the type based off of the first element in the literal, and then assumed that all other elements would be the same.
November 09, 2008
deadimp wrote:
> What's a 'good' way to initialize an array of references to classes using a common base? I've tried this and it works:
> 
> class Base
> {
>  void func();
> }
> class GoodChild : Base
> {
>  void func();
> }
> class BadChild : Base
> {
>  void func();
> }
> //...
> auto list = [cast(Base)new GoodChild, new BadChild, ...];
> 
> I had tried doing it without the initial cast, but ran into issues because D (DMD v1.033) would infer the type based off of the first element in the literal, and then assumed that all other elements would be the same.

	I would replace the last line with:
Base[] list = [ new GoodChild, new BadChild, ...];

	It's clearer, there's less typing and it won't suddenly fail if you
remove the first element and accidentally remove the cast at the
same time or if you add a new first element and forget to add the
cast...

		Jerome
- --
+------------------------- Jerome M. BERGER ---------------------+
|    mailto:jeberger@free.fr      | ICQ:    238062172            |
|    http://jeberger.free.fr/     | Jabber: jeberger@jabber.fr   |
+---------------------------------+------------------------------+
November 09, 2008
That's the problem I had mentioned, though - the type of the entire array being inferred from the first element rather than the context (i.e. what it's initializing if not declared as 'auto') or subsequent elements (which would be a bit difficult...).
When I try that, the compiler prints this error message: (formatted for this context)
"Error: cannot implicitly convert expression (new BadChild) of type BadChild to GoodChild"

I'm not sure what a good syntax replacement would be. C# / Java style new array instantiations wouldn't really fit in syntactically with the already established style of arrays. But maybe there's a way the type of an array coud be explicitly stated without having to cast to make the type inference correct.


Jérôme M. Berger Wrote:

> 	I would replace the last line with:
> Base[] list = [ new GoodChild, new BadChild, ...];
> 
> 	It's clearer, there's less typing and it won't suddenly fail if you
> remove the first element and accidentally remove the cast at the
> same time or if you add a new first element and forget to add the
> cast...
> 
> 		Jerome
November 09, 2008
deadimp escribió:
> That's the problem I had mentioned, though - the type of the entire array being inferred from the first element rather than the context (i.e. what it's initializing if not declared as 'auto') or subsequent elements (which would be a bit difficult...).
> When I try that, the compiler prints this error message: (formatted for this context)
> "Error: cannot implicitly convert expression (new BadChild) of type BadChild to GoodChild"
> 
> I'm not sure what a good syntax replacement would be. C# / Java style new array instantiations wouldn't really fit in syntactically with the already established style of arrays. But maybe there's a way the type of an array coud be explicitly stated without having to cast to make the type inference correct.
> 
> 
> Jérôme M. Berger Wrote:
> 
>> 	I would replace the last line with:
>> Base[] list = [ new GoodChild, new BadChild, ...];
>>
>> 	It's clearer, there's less typing and it won't suddenly fail if you
>> remove the first element and accidentally remove the cast at the
>> same time or if you add a new first element and forget to add the
>> cast...
>>
>> 		Jerome

Can't the compiler try to set the array's component type to the most general type of it's elements, by combining the most general types by pairs?

Hmmm... now that I think it, it's not that easy because of interfaces. Did this subject was ever discussed? If not, I'll try to think of an algorithm for this. (because if it was discussed, there must be a good reason for not doing this)
November 09, 2008
On Mon, Nov 10, 2008 at 6:47 AM, Ary Borenszweig <ary@esperanto.org.ar> wrote:
>
> Can't the compiler try to set the array's component type to the most general type of it's elements, by combining the most general types by pairs?
>
> Hmmm... now that I think it, it's not that easy because of interfaces. Did this subject was ever discussed? If not, I'll try to think of an algorithm for this. (because if it was discussed, there must be a good reason for not doing this)

I'm not sure what the problem is.  I think Walter likes the current
scheme because it's simple for the compiler and simple to explain.
Unfortunately I think it is counter to naive expectations, which means
that even though it's simple to explain, it *has* to be explained to
the uninitiated.
NumPy works the way you suggest.  It picks the most generic type that
can hold the answer.  I'm not sure what the algorithm is but it seems
to give adhere much better to the principle of least surprise.   But
maybe the fact that NumPy only cares about numeric types makes the
problem easier.  But I should would like it if this worked
     auto foo = [1,1,1,0.5];
and gave me a double[].
Anyway, that behavior seems to do what most people expeect.  On the
other hand I've seen this topic of picking the first element's type
come up several times here, generally because people didn't expect
that behavior..

--bb
November 10, 2008
Mebbe the naiive expectations arise because most compilers (those for D, C++, C#, C, Java) take the expression `15 + 0.6` and returns a double - the highest general 'blanketing' type - even though the first operand is an int. I forgot what this concept was called, though...

I would at least expect it when the variable has the type explicitly declared (`Base[] list`), since the following list would be seen as an initialization... Or is there another way that you initialize arrays, be they static or dynamic?

Bill Baxter Wrote:

> I'm not sure what the problem is.  I think Walter likes the current
> scheme because it's simple for the compiler and simple to explain.
> Unfortunately I think it is counter to naive expectations, which means
> that even though it's simple to explain, it *has* to be explained to
> the uninitiated.
> NumPy works the way you suggest.  It picks the most generic type that
> can hold the answer.  I'm not sure what the algorithm is but it seems
> to give adhere much better to the principle of least surprise.   But
> maybe the fact that NumPy only cares about numeric types makes the
> problem easier.  But I should would like it if this worked
>      auto foo = [1,1,1,0.5];
> and gave me a double[].
> Anyway, that behavior seems to do what most people expeect.  On the
> other hand I've seen this topic of picking the first element's type
> come up several times here, generally because people didn't expect
> that behavior..
> 
> --bb

November 10, 2008
Ary Borenszweig wrote:
> deadimp escribió:
>> That's the problem I had mentioned, though - the type of the entire array being inferred from the first element rather than the context (i.e. what it's initializing if not declared as 'auto') or subsequent elements (which would be a bit difficult...).
>> When I try that, the compiler prints this error message: (formatted for this context)
>> "Error: cannot implicitly convert expression (new BadChild) of type BadChild to GoodChild"
>>
>> I'm not sure what a good syntax replacement would be. C# / Java style new array instantiations wouldn't really fit in syntactically with the already established style of arrays. But maybe there's a way the type of an array coud be explicitly stated without having to cast to make the type inference correct.
>>
>>
>> Jérôme M. Berger Wrote:
>>
>>>     I would replace the last line with:
>>> Base[] list = [ new GoodChild, new BadChild, ...];
>>>
>>>     It's clearer, there's less typing and it won't suddenly fail if you
>>> remove the first element and accidentally remove the cast at the
>>> same time or if you add a new first element and forget to add the
>>> cast...
>>>
>>>         Jerome
> 
> Can't the compiler try to set the array's component type to the most general type of it's elements, by combining the most general types by pairs?
> 
> Hmmm... now that I think it, it's not that easy because of interfaces. Did this subject was ever discussed? If not, I'll try to think of an algorithm for this. (because if it was discussed, there must be a good reason for not doing this)

Ok, I wanted to see what does C# do with this. C# has the "var" keyword
that has the same semantic as "auto". Also, it has array initializers,
and today I found they come in two flavors:

{ x, y, z }        --> don't use type inference
new [] { x, y, z } --> use type inference

I can see the type of a "var" variable by hovering over it in Visual
Studio. Let's see:

var x = { 1, 2, 3 };
        // Error: cannot initialize an implicitly-typed
        // local variable with an array initializer

var x = new [] { 1, 2, 3 };    // ok, x is Int32[]
var x = new [] { 1, 2.0, 3 };  // ok, x is Double[]

Now with classes (object is root of all classes).

class A { }

class B { }

var x = new [] { new object(), new A() };  // ok, x is Object[]

var x = new [] { new A(), new B() };
        // Error: no base type for implicitly typed array

(the question here is, why not infer object[]?)

Without type deduction:

object[] x = new [] { new A(), new B() };
        // Error: no base type for implicitly typed array

But, without new []:

object[] x = { new A(), new B() }; // ok

In this last example, although no type can be inferred for the array
initializer, the compiler can see that each of it's elements can be cast
to object, and so doesn't give a compile error.

Why not implement this last behavior in D? I think this is a very common
case, and it seems easy to implement. I'll try to debug DMD's source code at night to see what can be changed for this to work... if there's interest.
November 10, 2008
On 2008-11-09 19:50, deadimp wrote:
> Mebbe the naiive expectations arise because most compilers (those for D, C++, C#, C, Java) take the expression `15 + 0.6` and returns a double - the highest general 'blanketing' type - even though the first operand is an int. I forgot what this concept was called, though... 
I believe it's called type promotion (see http://en.wikipedia.org/wiki/Type_polymorphism#Overloading).