inicio mail me! sindicaci;ón

What not to write in haXe

You might have notice that during the past few months i’ve written a few articles about haXe, a language and compiler which pits itself as a “toolbox for the web developer”.

Recently i decided to test out haXe’s platform support. I did this by taking my SCUMM interpreter code – which i had previously written for flash 9 – and tried to get it to work on the other two major platforms haXe supports, javascript and neko.

To start off with, i had to remove its dependency on flash. This was achieved by making replacement classes and switching between the two using the conditional pre-processor. i.e.:


#if flash9
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;
import flash.events.TimerEvent;
#else neko
import noflash.ByteArray;
import noflash.Bitmap;
import noflash.BitmapData;
import noflash.Point;
import noflash.Rectangle;
import noflash.Timer;
import noflash.TimerEvent;
#end

Most of the modifications to the code looked like this, with liberal sprinklings of ”#if flash9 … #end” round the flash specific code.

Eventually i got to the point where things started to look like they were going to compile, or so i thought

Problems

“Array too big”

The first problem i encountered was that it wouldn’t compile.


hiscumm/SCUMM6.hx:1870: lines 1870-2127 : This array declaration is too big, try to split it

Array declaration too big? What on earth was it going on about?


| TArrayDecl el ->
if List.length el > 115 then error "This array declaration is too big, try to split it" e.epos;
call p (field p (ident p "Array") "new1") [array p (List.map (gen_expr ctx) el); int p (List.length el)]

Oh, right. Seems i cannot have arrays declared with more than 115 elements. A seemingly arbitrary limitation that is not referenced anywhere in the documentation – great!

Not needing the opcode table for my little experiment, i commented most of it out. Problem solved.

“32bit? no, 31bit!”

Now the first time i got the interpreter to compile for neko, i thought “Wow, great! Looks like this is going to work.” Unfortunately though, it didn’t. Instead, i got a rather odd exception when reading out of my replacement ByteArray:


Uncaught exception - Overflow

Turns out the problem was with this code here, in neko.Input:


public function readInt32() {
var ch1 = readChar();
var ch2 = readChar();
var ch3 = readChar();
var ch4 = readChar();
if( (ch4 & 128) != 0 ) {
if( ch4 & 64 == 0 ) throw Error.Overflow;
return ch1 | (ch2 << 8) | (ch3 << 16) | ((ch4 & 127) << 24);
} else {
if( ch4 & 64 != 0 ) throw Error.Overflow;
return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
}
}

So basically the reader was trying to stuff the whole 32 bit value into a neko Integer, which is actually 31 bits. Oddly enough though, the value being read was identical to a value i specified in the code.

But haXe never bothered to complain about an overflow!

This can be demonstrated by the following code, which prints “-766623411” instead of the expected “1380860237”.


trace(1380860237);

Thankfully, a solution exists. There is an “Int32” type which properly handles 32bit integers. However there is a really big snag with it – it’s a class.

That means you cannot use any fancy inbuilt operators with it – you have to use a set of functions instead.


import neko.Int32;

var result: Int = 1 + 2; // simple
var result32: Int32 = Int32.add(Int32.ofInt(1), Int32.ofInt(2)); // aaaarrrghh!!!

result += 1; // simple
result32 += 1; // don't even think about it, it won't work

And to top it all off, this “Int32” class only exists for the neko platform, you cannot use it with flash or javascript. Unless you write it yourself, but that is besides the point. It should at least have been there to fill in the gap.

Conclusion

If you are looking at writing code in haXe and want it to work across all 3 of its supported platforms (flash*, neko and javascript), then beware if you are reading, writing, or otherwise processing 32bit integers.

In addition watch out for mysterious arbitrary limitations such as the 115 item limit for declared arrays.

Nicolas said,

March 1, 2008 @ 12:24 pm

For imports, you can do the following

// Common.hx

#if flash9
typedef Bitmap = flash.display.Bitmap;
typedef BitmapData = flash.display.BitmapData;
….
#else neko
typedef Bitmap = noflash.Bitmap;
typedef BitmapData = flash.display.BitmapData;

#end

Then from your code you only need to “import Common”.

The 115 Array Size is entirely arbitrary, it’s just a temporary bugfix for a current Neko compiler issue that will be addressed in next version.

31 bit integers are part of the Neko specification (see http://nekovm.org). It’s true that there is no crossplatform Int32 API right now, but that can easily be defined in haXe using inline methods.

James Urquhart said,

March 1, 2008 @ 10:12 pm

Many thanks for the suggestions, Nicholas! :)

I’m surprised that i didn’t figure that sticking the #ifdef’d stuff in Common.hx would be possible with haXe. Still, now i have an excuse to take a second look. :)

Nicolas said,

July 31, 2008 @ 11:20 am

You’ll be happy to know that with haXe 2.0 release :

- you can now remap packages with –remap flash:noflash (to fix your first problem)

- array bug has been fixed in neko 1.7.1

- there is crossplatform haxe.Int32 support (and crossplatform haxe.io + haxe.io.Bytes as well)

James Urquhart said,

August 1, 2008 @ 1:37 pm

Thanks again Nicolas! :)

Great to see all of those quirks fixed. My only criticism would be that Int32 is still not treated as a normal integer type, so code ends up filled with quirky looking “Int32.dothis(Int32.dothat())” statements. Would have thought if you could abstract the whole language onto another, you’d be able to abstract the Int32 as to act as an Int as well.

Regardless, i actually managed to compile hiscumm in haXe 2.0 with very minor modifications. Only problem is, to use the new haxe.Int32 stuff i have to re-do the whole IO code again. Eeek!

Still, i’m very pleased with haXe 2.0, and look forward to future uses of it in production environments. :)

RSS feed for comments on this post · TrackBack URI

Leave a Comment

Close
Powered by ShareThis