A literal array may get its type through top down inference. Assume you have this:
var a:Array<HasAnAge> = [p, p2, p3];
The compiler thus knows to check every entry in the literal against HasAnAge, so it is not unlike writing this:
var a = [(p:HasAnAge), (p2:HasAnAge), (p3:HasAnage)];
The next question is thus, why are Array<Person> and Array<HasAnAge> incompatible? The answer is, because Array is mutable and thus doesn't allow for variance. Here's why:
var a:Array<Person> = [p, p2, p3];
var b:Array<HasAnAge> = a;//let's assume this works
b.unshift({ age: 12 });
trace(Std.is(a[0], Person));//traces false
If it worked, it would create a type hole. But using an readonly type will work:
var a:Array<Person> = [p, p2, p3];
var b:Iterable<HasAnAge> = a;//this works
That's one way to tackle it. Another one would be this:
static function sum_age<A:HasAnAge>(people:Array<A>) {
var sum = 0;
for (a in people) sum += a.age;
a.push(a.pop());//not a problem, because all operations are performed on type A
trace('The sum of your ages is $sum');
}
I hope this clarifies things ^^
Best,
Juraj