HaXe tips and tricks

From Gnash Project Wiki

Jump to: navigation, search

Hopefully this page will be of use to people writing HaXe test cases for Gnash in the future, and for people trying to figure out HaXe in general.

Contents

General HaXe Notes

HaXe is a cross platform language and compiler. Users can compile into many different target languages including Flash and Javascript. Because of this, there are a few things that have been generalized so that they work on multiple targets. This can cause some problems. Another potential problem with HaXe is that id does not support every single class and function of Flash. In some cases it has a slightly different implementation of a class from the Flash, e.g. Array.

For Flash, HaXe attempts to turn what is essentially an untyped language in to a strongly typed one. The compiler does lot's of type checking, and it is sometimes hard to determine why it is throwing type errors. This has caused many problems when attempting to write test cases because we often want to test something that seems illogical. The proprietary player often allows the SWF to do unexpected things, (calling functions with bad arguments or too many arguments) with varying results, but Gnash should be able to handle this type of thing also.

The documentation for HaXe isn't all that bad if you are just starting out, and I recommend at least looking through some of the topics on the Language Reference page. The Documentation page also has some useful stuff, although I found the tutorials to be somewhat limited for our case. A few of the small general tidbits I learned while working to produce the Gnash test cases are:

  • HaXe seems to be able to do almost anything you want, you just have to be a little tricky
  • All HaXe files need to be classes in order for the compiler to know that you want to compile to ActionScript
    • (This may not be entirely true, but everything I've seen points to the necessity of a class definition)
  • The 'this' object is not always available in the same way as you might expect
  • for x in y loops do not seem to work the same way in HaXe as they do in ActionScript
  • HaXe has try..catch blocks, which were useful when testing flash9 errors that the proprietary player throws

In the end I believe we have converted all the ming tests (with maybe a few exeptions) to HaXe. Those that we have not yet converted are probably just a matter of playing with HaXe a little more.

The 'untyped' Keyword

Because HaXe is strongly typed, we have found that the HaXe keyword untyped can help get around certain compiler errors. This keyword is essentially a way to tell the compiler "hey, I don't want you to do any type checking on the following expression". Of course this is sort of dangerous, but ends up being necessary sometimes when you want to test something that HaXe does not normally allow. A lot of times this comes into play when there is not an equivalent class or function implemented in HaxXe. The hasOwnProperty global function in Flash is one of those that has been very useful in testing, but requires the use of the untyped keyword in Haxe. Examples:

 //For the BitmapData class
 var bdata = new BitmapData(200, 300);
 if( untyped bdata.hasOwnProperty('clone') ) { ... }

 //or for the Array class:
 var a1 = ['a', 'b', 'c'];
 if( untyped a1.hasOwnProperty('a') ) { ... }

Both of the above examples test for the existence of a property (remember functions and data are properties too).

The HaXe 'Magic'

Besides the useful untyped keyword, there are a number of other keywords that can be used to access some underlying flash functions that HaXe normally glosses over. These keywords are used in conjunction with untyped and allow access to things like 'instanceof', 'new', and 'typeof'. There is a page over on the HaXe website called The HaXe Magic (hence the section title) that details what these functions are and what they can do, but here are a few examples.

The 'typeof' keyword is useful for checking the Flash type of an item for instance:

 //This test is from TextFormat_as.hx
 if (Std.string(untyped __typeof__(x1.blockIndent) )== 'number'){
     DejaGnu.pass("TextFormat.blockIndent property exists");
 } else {
     DejaGnu.fail("TextFormat.blockIndent property should be float, returns type "+Type.typeof(x1.blockIndent));
 }

The __new__ keyword is useful when you want to call a constructor with arguments that HaXe doesn't recognize or with more or less arguments than HaXe is looking for:

 //This line from Rectangle_as.hx is used to call the constructor with no arguments.
 //HaXe does not normally allow this sort of thing
 var x1:Rectangle = untyped __new__(Rectangle);

There is also the __globabl__ keyword that allow you to access certain ActionScript 3 top level functions. If you can't figure out how to make something happen, there is a good chance there is one of the 'magic' keywords combined with untyped that will let you do what you want.

Unimplemented stuff in HaXe

There are a lot of classes and functions in Flash that the guys working on HaXe have not bothered to implement yet. Usually if you run into something like that you can get around it with untyped. In many cases a function is implemented with a certain number of arguments in HaXe, but Flash will accept either more or less arguments. In these cases, the Reflect.CallMethod function (see next section) will usually allow you to call a method with arguments that the HaXe compiler does not accept.

Std and Reflect classes in HaXe

The HaXe classes Std and Reflect provide many useful utilities that have been a big help in writing test cases. It is worth it to take some time to look at all the functions provided there.

Of particular note is the Reflect.callMethod function. Often we would like to call a method with arguments that seem to make sense but are invalid to make sure Gnash handles these correctly. Most of the time HaXe will catch these at compile time and throw an error about invalid or wrong number of arguments. You can use Reflect.CallMethod to force HaXe to call the method the way you want to call it.

 //Here in Array_as.hx we are using Reflect.CallMethod to call sort with no arguments on an array
 //HaXe doesn't normally like this
 Reflect.callMethod( gaparray, Reflect.field(gaparray, "sort"), []);

 //Here in Rectangle_as.hx we use it to call contains with unexpected arguments
 if (Type.typeof(Reflect.callMethod(x1, Reflect.field(x1, 'contains'), [0,'undefined'])) == ValueType.TNull)

The syntax is a little laborious, but it is the only way to get things done sometimes.

Another useful Reflect function is setField

A point should be made about the Std.is function. The 'instanceof' function does not exist in AS3, but Std.is seems to acheive the desired effect, probably because it traces the inheritance chain of an object. However, Std.is should not be used to check type because it seems to return some strange results at times. The __typeof__ function is much more desirable for checking type.

Subtle AS2 & AS3 differences

It is important to remember some of the subtle differences between AS2 and AS3 when creating test cases for Gnash. Some of the things that have thrown us for a loop are:

  • The __proto__ property does not exist in AS3
  • The 'prototype' property works differently between the two versions
  • Class inheritance works differently between the two versions

It is important to pay attention to the Adobe live docs concerning these differences. The Object class is a good place to start when trying to learn about these things.