Skip to content

Instantly share code, notes, and snippets.

@jdonaldson
Created October 11, 2011 17:42
Show Gist options
  • Save jdonaldson/1278814 to your computer and use it in GitHub Desktop.
Save jdonaldson/1278814 to your computer and use it in GitHub Desktop.
// Copyright (c) 2011, the HaXe project authors.
// All rights reserved.
// Simple test program to compare haXe style js output with dart version:
// https://gist.github.com/1277224
// compile: haxe -main HelloHaxeTest -js test.js
class HelloHaxeTest {
static function main() {
trace("Hello, HaXer!");
}
}
$estr = function() { return js.Boot.__string_rec(this,''); }
Std = function() { }
Std.__name__ = ["Std"];
Std["is"] = function(v,t) {
return js.Boot.__instanceof(v,t);
}
Std.string = function(s) {
return js.Boot.__string_rec(s,"");
}
Std["int"] = function(x) {
if(x < 0) return Math.ceil(x);
return Math.floor(x);
}
Std.parseInt = function(x) {
var v = parseInt(x,10);
if(v == 0 && x.charCodeAt(1) == 120) v = parseInt(x);
if(isNaN(v)) return null;
return v;
}
Std.parseFloat = function(x) {
return parseFloat(x);
}
Std.random = function(x) {
return Math.floor(Math.random() * x);
}
Std.prototype.__class__ = Std;
IntIter = function(min,max) {
if( min === $_ ) return;
this.min = min;
this.max = max;
}
IntIter.__name__ = ["IntIter"];
IntIter.prototype.min = null;
IntIter.prototype.max = null;
IntIter.prototype.hasNext = function() {
return this.min < this.max;
}
IntIter.prototype.next = function() {
return this.min++;
}
IntIter.prototype.__class__ = IntIter;
HelloHaxeTest = function() { }
HelloHaxeTest.__name__ = ["HelloHaxeTest"];
HelloHaxeTest.main = function() {
haxe.Log.trace("Hello, HaXer!",{ fileName : "HelloHaxeTest.hx", lineNumber : 9, className : "HelloHaxeTest", methodName : "main"});
}
HelloHaxeTest.prototype.__class__ = HelloHaxeTest;
if(typeof haxe=='undefined') haxe = {}
haxe.Log = function() { }
haxe.Log.__name__ = ["haxe","Log"];
haxe.Log.trace = function(v,infos) {
js.Boot.__trace(v,infos);
}
haxe.Log.clear = function() {
js.Boot.__clear_trace();
}
haxe.Log.prototype.__class__ = haxe.Log;
if(typeof js=='undefined') js = {}
js.Lib = function() { }
js.Lib.__name__ = ["js","Lib"];
js.Lib.isIE = null;
js.Lib.isOpera = null;
js.Lib.document = null;
js.Lib.window = null;
js.Lib.alert = function(v) {
alert(js.Boot.__string_rec(v,""));
}
js.Lib.eval = function(code) {
return eval(code);
}
js.Lib.setErrorHandler = function(f) {
js.Lib.onerror = f;
}
js.Lib.prototype.__class__ = js.Lib;
js.Boot = function() { }
js.Boot.__name__ = ["js","Boot"];
js.Boot.__unhtml = function(s) {
return s.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
}
js.Boot.__trace = function(v,i) {
var msg = i != null?i.fileName + ":" + i.lineNumber + ": ":"";
msg += js.Boot.__unhtml(js.Boot.__string_rec(v,"")) + "<br/>";
var d = document.getElementById("haxe:trace");
if(d == null) alert("No haxe:trace element defined\n" + msg); else d.innerHTML += msg;
}
js.Boot.__clear_trace = function() {
var d = document.getElementById("haxe:trace");
if(d != null) d.innerHTML = "";
}
js.Boot.__closure = function(o,f) {
var m = o[f];
if(m == null) return null;
var f1 = function() {
return m.apply(o,arguments);
};
f1.scope = o;
f1.method = m;
return f1;
}
js.Boot.__string_rec = function(o,s) {
if(o == null) return "null";
if(s.length >= 5) return "<...>";
var t = typeof(o);
if(t == "function" && (o.__name__ != null || o.__ename__ != null)) t = "object";
switch(t) {
case "object":
if(o instanceof Array) {
if(o.__enum__ != null) {
if(o.length == 2) return o[0];
var str = o[0] + "(";
s += "\t";
var _g1 = 2, _g = o.length;
while(_g1 < _g) {
var i = _g1++;
if(i != 2) str += "," + js.Boot.__string_rec(o[i],s); else str += js.Boot.__string_rec(o[i],s);
}
return str + ")";
}
var l = o.length;
var i;
var str = "[";
s += "\t";
var _g = 0;
while(_g < l) {
var i1 = _g++;
str += (i1 > 0?",":"") + js.Boot.__string_rec(o[i1],s);
}
str += "]";
return str;
}
var tostr;
try {
tostr = o.toString;
} catch( e ) {
return "???";
}
if(tostr != null && tostr != Object.toString) {
var s2 = o.toString();
if(s2 != "[object Object]") return s2;
}
var k = null;
var str = "{\n";
s += "\t";
var hasp = o.hasOwnProperty != null;
for( var k in o ) { ;
if(hasp && !o.hasOwnProperty(k)) {
continue;
}
if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__") {
continue;
}
if(str.length != 2) str += ", \n";
str += s + k + " : " + js.Boot.__string_rec(o[k],s);
}
s = s.substring(1);
str += "\n" + s + "}";
return str;
case "function":
return "<function>";
case "string":
return o;
default:
return String(o);
}
}
js.Boot.__interfLoop = function(cc,cl) {
if(cc == null) return false;
if(cc == cl) return true;
var intf = cc.__interfaces__;
if(intf != null) {
var _g1 = 0, _g = intf.length;
while(_g1 < _g) {
var i = _g1++;
var i1 = intf[i];
if(i1 == cl || js.Boot.__interfLoop(i1,cl)) return true;
}
}
return js.Boot.__interfLoop(cc.__super__,cl);
}
js.Boot.__instanceof = function(o,cl) {
try {
if(o instanceof cl) {
if(cl == Array) return o.__enum__ == null;
return true;
}
if(js.Boot.__interfLoop(o.__class__,cl)) return true;
} catch( e ) {
if(cl == null) return false;
}
switch(cl) {
case Int:
return Math.ceil(o%2147483648.0) === o;
case Float:
return typeof(o) == "number";
case Bool:
return o === true || o === false;
case String:
return typeof(o) == "string";
case Dynamic:
return true;
default:
if(o == null) return false;
return o.__enum__ == cl || cl == Class && o.__name__ != null || cl == Enum && o.__ename__ != null;
}
}
js.Boot.__init = function() {
js.Lib.isIE = typeof document!='undefined' && document.all != null && typeof window!='undefined' && window.opera == null;
js.Lib.isOpera = typeof window!='undefined' && window.opera != null;
Array.prototype.copy = Array.prototype.slice;
Array.prototype.insert = function(i,x) {
this.splice(i,0,x);
};
Array.prototype.remove = Array.prototype.indexOf?function(obj) {
var idx = this.indexOf(obj);
if(idx == -1) return false;
this.splice(idx,1);
return true;
}:function(obj) {
var i = 0;
var l = this.length;
while(i < l) {
if(this[i] == obj) {
this.splice(i,1);
return true;
}
i++;
}
return false;
};
Array.prototype.iterator = function() {
return { cur : 0, arr : this, hasNext : function() {
return this.cur < this.arr.length;
}, next : function() {
return this.arr[this.cur++];
}};
};
if(String.prototype.cca == null) String.prototype.cca = String.prototype.charCodeAt;
String.prototype.charCodeAt = function(i) {
var x = this.cca(i);
if(x != x) return null;
return x;
};
var oldsub = String.prototype.substr;
String.prototype.substr = function(pos,len) {
if(pos != null && pos != 0 && len != null && len < 0) return "";
if(len == null) len = this.length;
if(pos < 0) {
pos = this.length + pos;
if(pos < 0) pos = 0;
} else if(len < 0) len = this.length + len - pos;
return oldsub.apply(this,[pos,len]);
};
$closure = js.Boot.__closure;
}
js.Boot.prototype.__class__ = js.Boot;
$_ = {}
js.Boot.__res = {}
js.Boot.__init();
{
String.prototype.__class__ = String;
String.__name__ = ["String"];
Array.prototype.__class__ = Array;
Array.__name__ = ["Array"];
Int = { __name__ : ["Int"]};
Dynamic = { __name__ : ["Dynamic"]};
Float = Number;
Float.__name__ = ["Float"];
Bool = { __ename__ : ["Bool"]};
Class = { __name__ : ["Class"]};
Enum = { };
Void = { __ename__ : ["Void"]};
}
{
Math.__name__ = ["Math"];
Math.NaN = Number["NaN"];
Math.NEGATIVE_INFINITY = Number["NEGATIVE_INFINITY"];
Math.POSITIVE_INFINITY = Number["POSITIVE_INFINITY"];
Math.isFinite = function(i) {
return isFinite(i);
};
Math.isNaN = function(i) {
return isNaN(i);
};
}
{
js.Lib.document = document;
js.Lib.window = window;
onerror = function(msg,url,line) {
var f = js.Lib.onerror;
if( f == null )
return false;
return f(msg,[url+":"+line]);
}
}
js.Lib.onerror = null;
HelloHaxeTest.main()
@millermedeiros
Copy link

better than dart but could be way better... in my opinion 296 lines still seems a lot, I think it should only output what is really needed to run the code and also provide a way to compile the project into multiple files and not output haxe boilerplate code. It generates global variables without any reason, relies a lot in complex namespacing, extend natives prototypes (which can cause conflicts with other libraries), etc...

I think one of the reasons why CoffeeScript got so popular is that the output doesn't scares JavaScript developers and you can use the code as if it was a regular JS project/library...

I sent an email to the haXe mailing list last year telling those things but I've been coding so much JS that I got used to it and don't feel like switching to Dart/haXe/CoffeeScript anytime soon. JavaScript becomes awesome after you understand it and start using the "right" tools/workflow...

@jdonaldson
Copy link
Author

There's a difference between what haxe/dash are doing, and what coffeescript is doing. Coffeescript is not designed to be useful for complex web applications. It's just syntactic sugar for doing simple map operations, object declarations, and other misc operations.

In HaXe, the global variables are there in order to keep some basic functionality consistent. You can add your own namespace with --js-namespace : haxe.org/manual/metadata

The complex namespaces are an unfortunate aspect of dealing with the lack of namespacing in javascript. You appreciate having such namespaces once you start using other complex libraries. As long as you stick with haxe and haxe externs, you will have a much better chance of keeping things from colliding.

It would be nice to not have to extend native prototypes to avoid a conflict. But, it takes two to tango. If there's a conflict, that means somebody else's library did it as well. Unfortunately, there's not a good workaround. Using new prototypes for things like arrays and strings would mean that you couldn't use simple value declarations like "string" or [a,r,r,a,y]. If the compiler translated this into some other form of new haxe object, performance would decrease, and it would add a lot of junk to every string declaration (e.g. HaxeString("blah blah blah")). This would make debugging even more difficult, and potentially still cause conflicts inside the haxe libraries. I've never run into any native extension conflicts yet fwiw.

@millermedeiros
Copy link

I'm aware of the differences and the --js-namespace option and know that haXe needs the Std libs since it wants to provide a similar dev experience no matter the target language, which is an awesome feature BTW, just think that output could be way more optimized (execution performance, minification friendly, readable, etc).

Name collision can be avoided by other ways (closures, hash table) and having deep lookup trees is a bad thing for execution performance and for minification.

I see haXe as an awesome language for cross-platform development but I can't see it being used on sites like BBC, Yahoo, GMail, or any other large site that cares a lot about page load performance or as a real replacement to JavaScript (since haXe libraries can't be used outside a haXe project)..

This post describes exactly how I fell about JavaScript nowadays: evolution of a prototypal language user

And this quote is also really good:

If you like Java and can’t get yourself to like JavaScript, you program Dart.
If you like Ruby and can’t get yourself to like JavaScript, you program CoffeeScript.
If you like JavaScript, you program JavaScript.

(from: Dart; or Why JavaScript has already won)

cheers.

@jdonaldson
Copy link
Author

Name collision and sophisticated namespaces go hand in hand. I can't see how one could criticize the way that haxe does it, and then be perfectly fine with better.js modules. I can appreciate how better.js works efficiently with javascript, but I'm hoping you will agree with me that it is hardly elegant.

As far as performance goes, namespace access speed is less of an issue with more modern browsers, and can be optimized anyways (using local copies) with minimal effort. HaXe also helps you with simple things like avoiding accidentally leaving out var declarations.

Thanks for all of the links, I haven't seen some of them yet.
Also, considering that last blog about Dart, consider that Flash had "already won" as well. It was arguably installed in more browsers/devices than javascript was, and faster. And, you didn't need such strange approaches towards building complex applications. Granted, many things about Flash were horrible... the proprietary editor, the lack of typed Arrays, the closed nature of the whole eco-system, I could go on. Point is, it's now suddenly out of fashion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment