Why do array literals default to object.Object[]?

Steven Schveighoffer via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Jul 11 19:06:41 PDT 2017


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


More information about the Digitalmars-d-learn mailing list