Casting in Haxe

Hi. How can I make the following piece of code work?

public function myFunction<T>():Array<T>
{
  var array = new Array<T>();
  var v:T;

  if(Std.is(v, Bool))
    array.unshift(false); // doesn't work
  else
    array.unshift(null);

  return array;
}

It’s a casting problem, I think. Also, do | really need the v, or is there another way?

Could you be more specific? I mean if you shift/unshift your array array cannot you just take the first element to check for its class like var v:T = array.pop();? By doesn't work you mean array.unshift(false); it is never called or it does not compile at all ? Isn’t that var v:T; useless because you’ve got a null in there so it is never Bool - it’s probably Null<T> so in your specific case it is just null.

Well, let’s be a bit more precise. I’m trying to write a function that receives a size and returns an array of that size filled with items that obey the following rule: if T is Bool, the items are all false; if T is Int, the items are all 0; if T is Float, the items are all 0.0; otherwise, the items are all null. This is my current attempt:

public function initialize<T>(size:Int):Array<T>
{
  var array = new Array<T>();

  if(Std.is(array, ArrayBool))
  {
    for(i in 0...size)
      array.unshift(cast false);
  }
  else if(Std.is(array, ArrayInt))
  {
    for(i in 0...size)
      array.unshift(cast 0);
  }
  else if(Std.is(array, ArrayFloat))
  {
    for(i in 0...size)
      array.unshift(cast 0.0);
  }
  else
  {
    for(i in 0...size)
      array.unshift(null);
  }

  return array;
}

Of course, elsewhere, I have:

typedef ArrayBool = Array<Bool>;
typedef ArrayInt = Array<Int>;
typedef ArrayFloat = Array<Float>;

This attempt compiles, however, the array is always filled with false. Can you tell me what I’m doing wrong?

By using typedefs, you’re just tricking the compiler into compiling a Std.is() check with type parameters. However, this doesn’t work, since type parameters don’t exist at runtime. Because of that, Std.is(array, ArrayBool) is the same as checking Std.is(array, Array), and since that’s the first if in the chain, it will always trigger.

What you want to accomplish is a bit tricky, perhaps you could emulate something like C#'s default(T) using an expression macro.

We ended up having to use multiple underlying base classes in order to properly implement this behavior in Haxe for openfl.Vector.

You could look at the source code, but it’s complicated. The best recommendation I can give you at the moment is to use openfl.Vector with a fixed size, and we’ll give you an object that’s already initialized with 0.0, 0, null or false based on the parameter type.

I see. If I understand correctly, there is no way of knowing at runtime what type T actually is, because T is a compile-time entity only. I’ll have a go at openfl.Vector, then. Thanks!

1 Like

You are probably accustomed to dynamically-typed (or typeless) languages – such as Visual Basic (.NET) or JavaScript – which routinely express data as “self-describing objects” which include both the data itself and an indicator as to its [current] type. Each operation that is performed against such objects is therefore able to “do the right thing in all cases” since “the data describes itself.”

With static typing, however, everything occurs at compile time. The data itself, as it actually appears in memory, contains no indication as to “what type” it is. In fact, the entire notion is meaningless – “the data itself” consists only of bytes, and these bytes are not self-describing in any way.

This just popped up:

  public function initialize<T>(size:Word, defaultValue:T):Array<T>
  {
    if(size == 0)
      return null;
    else
      return [for(i in 0...size) defaultValue];
  }

It’s not very elegant, but it’s simple and it serves my purposes.

On C++, you might also get faster performance if you add @:generic to this method