Let's say I have the following type:
class InABox<T>
{
public function new() {}
public var t: T;
}
Oh wow, IntelliJ copies colours. Awesome. Anyway, I decide to make a bunch of these things each with a different T.
var a = new InABox<Int>();
var b = new InABox<Float>();
var c = new InABox<Bool>();
var d = new InABox<String>();
What's surprising to me is that I'm allowed to put them all in an array like so:
var list: Array<InABox<Dynamic>> = [ a, b, c, d ];
I fully expected that assignment to fail, but it doesn't. Hey cool. It does say in the documentation that type parameters are bound on instantiation, so it makes sense to me that the four InABox instances aren't necessarily of disparate types in compile time.
The thing is though, now it seems my code is in a weird place, because list[0] is statically typed to InABox<Dynamic> but the instance was actually made as a type InABox<Int>.
So the obvious next step is to assign a string to it, to watch the code crash and burn.
list[0].t = "hi there";
list[1].t = "hi there";
list[2].t = "hi there";
list[3].t = "hi there";
trace(a.t); // 0
trace(b.t); // NaN
trace(c.t); // true
trace(d.t); // "hi there"
But it doesn't crash and burn. It just sort of ... doesn't work? There's no actual error and execution continues normally. It seems to just be going with the best values it can. But I'm just not sure what is going on here. It's obvious to me that this code is Not a Good Idea. But normally assigning "hi there" to a field of type Int would not even be an allowed statement, yet in this situation it's running fine.
What are the rules in this situation and what is the mechanism behind the scenes that makes it work?