Search code examples
haxe

How to convert Haxe Array/Vector to another type


Let's say I've got an array or vector of some parent type. To pass it to a function, I need it to be some child type (which I know beforehand that all elements are guaranteed to be all that child type). Is there a convenient way to do that? Right now I can only think to make a whole new array.

Also, it looks like it won't let me do it the other way around: it won't accept an array of child type in the place of the parent type. Is there a good way to solve this situation as well?

It looks like cast v works, but is this the preferred way?


Solution

  • To pass it to a function, I need it to be some child type (which I know beforehand that all elements are guaranteed to be all that child type).

    If you really are confident that that's the case, it is safe to use a cast. I don't think there's any prettier way of doing this, nor should there be, as it inherently isn't pretty. Having to do this often indicates a design flaw in your code or the API that is being used.


    For the reverse case, it's helpful to understand why it's not safe. The reason is not necessarily as intuitive because of this thought process:

    I can assign Child to Base, so why can't I assign Array<Child> to Array<Base>?

    This exact example is used to explain Variance in the Haxe Manual. You should definitely read it in full, but I'll give a quick summary here:

    var children = [new Child()];
    var bases:Array<Base> = cast children;
    bases.push(new OtherChild());
    
    children[1].childMethod(); // runtime crash
    

    If you could assign the Array<Child> to an Array<Base>, you could then push() types that are incompatible with Child into it. But again, as you mentioned, you can just cast it to silence the compiler as in the code snippet above.

    However, this is not always safe - there might still be code holding a reference to that original Array<Child>, which now suddenly contains things that it doesn't expect! This means we could do something like calling childMethod() on an object that doesn't have that method, and cause a runtime crash.

    The opposite is also true, if there's no code holding onto such a reference (or if the references are read-only, for instance via haxe.ds.ReadOnlyArray), it is safe to use a cast.


    At the end of the day it's a trade-off between the performance cost of making a copy (which might be negligible depending on the size) and how confident you are that you're smarter than the compiler / know about all references that exist.