www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why do array literals default to object.Object[]?

reply Brandon Buck <lordizuriel gmail.com> writes:
I apologize if this has been touched on before, I'm not quite 
sure what to search for and what I did try didn't bring anything 
up.

Okay, so I'm learning D, using the D Tour flow and I went over 
interfaces. Everything is making sense. I key in the example (as 
I like to copy it by hand and then run it locally instead of 
online) and I attempt to make a slight alteration. In the 
previous example, with base classes, the main method begins with:


Any[] anys = [
     new Integer(10),
     new Float(3.1415f)
];

Which makes sense. Integer and Float in that example are both 
inheriting from Any. So when doing the example with interfaces 
where Dog and Cat both inherit from the interface Animal, I first 
tried:

auto animals = [
     new Dog,
     new Cat
];

But got this error:

interfaces.d(51): Error: no property 'multipleNoise' for type 
'object.Object'

Which implies (to me) the auto inferred object.Object, this makes 
sense though. Without basic type inspection they're both classes 
and object.Object is the most reasonable parent of them both. 
Fine. I adjusted my code to better match the class example:

Animal[] animals = [
     new Dog,
     new Cat
];

Surely this works:

interfaces.d(47): Error: cannot implicitly convert expression 
([new Dog, new Cat]) of type Object[] to Animal[]

Different _message_ but same issue. It's inferring Object[]. I've 
told it explicitly that it's an Animal[], and both classes 
inherit from Animal (as the solution and the example on the tour 
page) demonstrate:

Animal dog = new Dog;
Animal cat = new Cat;
Animal[] animals = [dog, cat];

So they can be assigned to Animal fine, but even using them in an 
expression tagged with Animal[] still produces an Object[] value. 
Is this intentional? It feels unintuitive. I understand why auto 
infers Object[] and that make sense, but if I'm using the actual 
type (Animal[]) and can work the long way around to the same type 
(the last example), why can't I do it via direct assignment to 
Animal[]?
Jul 11 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/11/17 9:27 PM, Brandon Buck wrote:
 I apologize if this has been touched on before, I'm not quite sure what 
 to search for and what I did try didn't bring anything up.
 
 Okay, so I'm learning D, using the D Tour flow and I went over 
 interfaces. Everything is making sense. I key in the example (as I like 
 to copy it by hand and then run it locally instead of online) and I 
 attempt to make a slight alteration. In the previous example, with base 
 classes, the main method begins with:
 
 
 Any[] anys = [
      new Integer(10),
      new Float(3.1415f)
 ];
 
 Which makes sense. Integer and Float in that example are both inheriting 
 from Any. So when doing the example with interfaces where Dog and Cat 
 both inherit from the interface Animal, I first tried:
 
 auto animals = [
      new Dog,
      new Cat
 ];
 
 But got this error:
 
 interfaces.d(51): Error: no property 'multipleNoise' for type 
 'object.Object'
 
 Which implies (to me) the auto inferred object.Object, this makes sense 
 though. Without basic type inspection they're both classes and 
 object.Object is the most reasonable parent of them both. Fine. I 
 adjusted my code to better match the class example:
 
 Animal[] animals = [
      new Dog,
      new Cat
 ];
 
 Surely this works:
 
 interfaces.d(47): Error: cannot implicitly convert expression ([new Dog, 
 new Cat]) of type Object[] to Animal[]
 
 Different _message_ but same issue. It's inferring Object[]. I've told 
 it explicitly that it's an Animal[], and both classes inherit from 
 Animal (as the solution and the example on the tour page) demonstrate:
In some cases, the declaration does not participate in the type inference. It's still looking at the expression [new Dog, new Cat] separately from the declaration of the array. The problem is that it has multiple "trees" to go down. Both can be Objects, both can be Animals, which one did you really mean? You can override this with a cast: auto animals = cast(Animal[])[new Dog, new Cat]; Or you can cast the first item to tell the inference which tree to go down. auto animals = [cast(Animal)new Dog, new Cat]; I do agree it's not intuitive for an initializer, especially when: auto a = [1, 2, 3]; // typeof(a) == int[] short[] b = [1, 2, 3]; // works I'm sure there's a bug filed somewhere on this...
 So they can be assigned to Animal fine, but even using them in an 
 expression tagged with Animal[] still produces an Object[] value. Is 
 this intentional? It feels unintuitive. I understand why auto infers 
 Object[] and that make sense, but if I'm using the actual type 
 (Animal[]) and can work the long way around to the same type (the last 
 example), why can't I do it via direct assignment to Animal[]?
Note that an interface reference is not the same as a class reference. You can see the difference here: auto d = new Dog; Animal a = d; writefln("%x, %x", cast(void*)d, cast(void*)a); // prints 2 different addresses An interface reference can't be "reinterpret cast" to an Object, or even another interface, it just will result in crashes. So you can't cast an array like that either, you'd have to copy the array, or modify it. -Steve
Jul 11 2017
parent reply Brandon Buck <lordizuriel gmail.com> writes:
On Wednesday, 12 July 2017 at 02:06:41 UTC, Steven Schveighoffer 
wrote:
 I do agree it's not intuitive for an initializer, especially 
 when:

 auto a = [1, 2, 3]; // typeof(a) == int[]
 short[] b = [1, 2, 3]; // works
Thank you for getting back to me, that's where my train of thought was going. While I know it's not _really_ valid to say "this other language does it," my experience does hail from elsewhere where this would be perfectly legal.
 I'm sure there's a bug filed somewhere on this...
Is this bug worthy? I can search for one and comment and/or create one if I can't find one.
 auto d = new Dog;
 Animal a = d;
 writefln("%x, %x", cast(void*)d, cast(void*)a); // prints 2 
 different addresses
That's also an interesting observation.
Jul 11 2017
next sibling parent Moritz Maxeiner <moritz ucworks.org> writes:
On Wednesday, 12 July 2017 at 05:24:49 UTC, Brandon Buck wrote:
 On Wednesday, 12 July 2017 at 02:06:41 UTC, Steven 
 Schveighoffer wrote:

 I'm sure there's a bug filed somewhere on this...
Is this bug worthy? I can search for one and comment and/or create one if I can't find one.
It's at best very unintuitive behaviour (I had expected the inference to go up from the class type to Object, not down from Object), so I'd say yes.
Jul 13 2017
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/12/17 1:24 AM, Brandon Buck wrote:
 On Wednesday, 12 July 2017 at 02:06:41 UTC, Steven Schveighoffer wrote:
 I'm sure there's a bug filed somewhere on this...
Is this bug worthy? I can search for one and comment and/or create one if I can't find one.
Found it. It was mistakenly closed: https://issues.dlang.org/show_bug.cgi?id=12283 -Steve
Jul 13 2017