www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Array initialization with common base - Best way?

reply deadimp <deadimp gmail.com> writes:
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. 
Nov 08 2008
parent reply =?windows-1252?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

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 | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkkWvUEACgkQd0kWM4JG3k/+lQCfTvFvrT5CmEhC0z5r11Esj5Cv IckAn1csTb5QyDZr2icXHfDKqYDMKC0w =SXsh -----END PGP SIGNATURE-----
Nov 09 2008
next sibling parent reply deadimp <deadimp gmail.com> writes:
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

Nov 09 2008
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
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)
Nov 09 2008
next sibling parent reply deadimp <deadimp gmail.com> writes:
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

Nov 09 2008
parent Carl Clark <carlclark lavabit.com> writes:
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... 

http://en.wikipedia.org/wiki/Type_polymorphism#Overloading).
Nov 10 2008
prev sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
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.
Nov 10 2008
prev sibling parent "Bill Baxter" <wbaxter gmail.com> writes:
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
Nov 09 2008