Hey,
I'm evaluating Haxe for use in a project using JS, PHP and Java, and been very impressed so far. But I've been running some tests and the generated Java code for some stuff looks way less efficient and optimised than the JS and PHP targets.
E.g. this simple chunk of Haxe:
[1, 2, 3].map(function (v) return v * 4).filter(function(v) return v > 1);
produces this perfect JS:
[1,2,3].map(function(v) {
... and this pretty efficient PHP (I dug through the _hx functions and they all look nimble enough, though I was surprised that native PHP array_filter and array_map aren't used):
_hx_deref((new _hx_array(array(1, 2, 3))))->map(array(new _hx_lambda(array(), "ScreenTest_0"), 'execute'))->filter(array(new _hx_lambda(array(), "ScreenTest_1"), 'execute'));
function ScreenTest_0($v) {
function ScreenTest_1($v1) {
But then there's this for Java:
((haxe.root.Array<java.lang.Object>) (((haxe.root.Array) (new haxe.root.Array<java.lang.Object>(new java.lang.Object[]{1, 2, 3}).map(((haxe.lang.Function) (( (( haxe.root.ScreenTest_render_58__Fun.__hx_current != null )) ? (haxe.root.ScreenTest_render_58__Fun.__hx_current) : (haxe.root.ScreenTest_render_58__Fun.__hx_current = ((haxe.root.ScreenTest_render_58__Fun) (new haxe.root.ScreenTest_render_58__Fun()) )) )) ))) )) ).filter(( (( haxe.root.ScreenTest_render_58__Fun_0.__hx_current != null )) ? (haxe.root.ScreenTest_render_58__Fun_0.__hx_current) : (haxe.root.ScreenTest_render_58__Fun_0.__hx_current = ((haxe.root.ScreenTest_render_58__Fun_0) (new haxe.root.ScreenTest_render_58__Fun_0()) )) ));
with a class generated for the lambda:`
@SuppressWarnings(value={"rawtypes", "unchecked"})
public class ScreenTest_render_58__Fun extends haxe.lang.Function
public ScreenTest_render_58__Fun()
//line 58 "e:\\dev\\all3\\RankPress SEO\\ScreenTest.hx"
public static haxe.root.ScreenTest_render_58__Fun __hx_current;
@Override public double __hx_invoke1_f(double __fn_float1, java.lang.Object __fn_dyn1)
//line 58 "e:\\dev\\all3\\RankPress SEO\\ScreenTest.hx"
int v = ( (( __fn_dyn1 == haxe.lang.Runtime.undefined )) ? (((int) (__fn_float1) )) : (((int) (haxe.lang.Runtime.toInt(__fn_dyn1)) )) );
//line 58 "e:\\dev\\all3\\RankPress SEO\\ScreenTest.hx"
return ((double) (( v * 4 )) );
(with another class for the second lambda).
Apart from the sheer relative size and unreadability of the Java code, there look to be a few performance nasties here. This "haxe.lang.Runtime.toInt(__fn_dyn1))" doesn't look wonderful, there's a lot of new-ing, and when I have a look at map() in Array.java, it seems to be an unoptimised straight conversion of the Haxe code.
I don't mean this to be critical, I know someone's spent a lot of time on the Java target. It's just that I rely heavily on map/filter/lambda and this unoptimised output is kinda offputting and makes me wary about adopting Haxe on a large scale.
Incidentally, I had a look at the other major targets, and the C# output is very similar to the Java, but the C++ target looks optimised and fast (though it doesn't use native C++11 lambdas).
Is the Java target still actively worked on? New Java 8 features (stream, map, filter, lambda) could make this code a lot faster - perhaps a new java8 target could be added?