TypeScript vs. Haxe
blog.onthewings.net
blog.onthewings.net
This quote fits the spirit of the article well, in missing the most important point about TypeScript: the driving principle of TypeScript is, and always has been, to resemble JavaScript as closely as possible. The point is to be a superset of JavaScript. How would you do that if you start changing the semantics of existing constructs?
It's just one quote, but the rest of the article carries the same smell. Telling omission: the comparison between the compiled versions of the presented code snippets. TypeScript code emission tries to resemble the original JS. How does Haxe hold up?
I do not doubt for a second that Haxe, as a language, is better than TypeScript. I don't know it, but it's not a hard task. Almost any language is better than TypeScript. The only one that isn't, in fact, is JavaScript.
Being a good language was never the point of TypeScript. Just being better than JS, while resembling it so much that nobody in their right mind could make a compelling argument against it, but in favor of JS.
EDIT: larsiusprime makes a good point, which I would have noticed had I actually read the conclusion instead of stopping half-way through: the author already addresses this.
"However, at the core, TypeScript and Haxe have different design philosophies. TypeScript is a superset of JS. It means it cannot modify the existing JS syntax and semantics. It adds a static type system and some new constructs (e.g. “proper” class/interface). It is not interested in optimizing the program in any way. Haxe looks like JS, but is more similar to other popular compiled languages like Java/C# regarding to semantics, the use of types, code organization, and optimizations. It also brings in a lot of advanced functional programming concepts.
Which is the better compile-to-JS language? It depends. Existing JS developers will favor TypeScript as they are more similar in many ways. They can utilize their existing skills immediately."
EDIT:
As for how Haxe holds up on generated JS code, you can see for yourself online right here:
Typescript on the other hand produces the ES5 that I would have written if I wasn't using Typescript. Variable names are kept, nothing is elided. You can even ask Typescript to translate code with type errors and it happily compiles.
Specifically, Haxe's output is here: https://gist.github.com/mattmccray/3916195#file-haxe-js
In my opinion it is super readable.
It transpiles your code to a small lump of useful code. It also includes a runtime library which takes up a chunk of space. That ends up being a large fraction of the overall result when the application in question is "hello, world!", but in a real-world app, it's a relatively small piece of the pie.
I'll also note that the Gist is from 2012. Dart is twice as old today as it was when that Gist was published.
Here's what the output looks like today [1]. We have two compilers right now:
dart2js is designed to produce output that runs as fast as possible and is as small as possible. You can think of it as "-O3". Optimize all the things at the expense of readability. The dart2js output on the simple example is 170 lines, or 5K of JS (before gzip). Still kind of big, but like I said, most of that is runtime library that amortizes better in large programs.
dev_compiler, or "ddc" is for producing human-readable, debuggable output. It's like "gcc -g". No optimizations or minifications, fast compile times, maximum readability. Its output for this is 29 lines. This does not include the runtime library, since it compiles that to separate (also readable) files. The output uses ES6 and looks like:
dart_library.library('simple', null, /* Imports */[
"dart_runtime/dart",
'dart/core'
], /* Lazy imports */[
], function(exports, dart, core) {
'use strict';
let dartx = dart.dartx;
class Simple extends core.Object {
Simple(name) {
this.name = name;
}
greet(who) {
return `Greetings ${who}, I'm ${this.name}!`;
}
}
dart.setSignature(Simple, {
constructors: () => ({Simple: [Simple, [core.String]]}),
methods: () => ({greet: [dart.dynamic, [dart.dynamic]]})
});
function main() {
let s = new Simple('Flyn');
core.print(s.greet('Program'));
}
dart.fn(main);
// Exports:
exports.Simple = Simple;
exports.main = main;
});
//# sourceMappingURL=simple.js.map
Pretty readable, I think, especially given how young ddc is. The team is still hard at work on it.[1]: https://gist.github.com/munificent/bde42b3d02c563fb4a9c
dart2js is designed to produce output that runs as fast as possible and is as small as possible.
Speaking of small: What's the size of the dart_runtime/dart and dart/core that seemingly always gets imported?Typescript: 15 lines
Haxe: 18 lines
Coffeescript: 26 lines
JSX: 228 lines
Dart: 791 lines
From the acceptance of ES6 forward, JS devs (and devs of whatever languages consider themselves to be a superset of JS) need to accept that both function scope and block scope exist in the language.
I wrote a lot of features that I used to need in gulp (+ plugins) in Haxe, which is a great way of learning to use it, and a great way to find out how nice it is to have type safety.
Also, the language allows a simple JS / AS dev like me to build multithreaded apps that carry extremly heavy weights.
I can't wait to learn it.
As a language Haxe has some interesting features (although when compared with the other languages I chose (Nim, OCaml, Dylan, C++, Racket, Tcl...) they look fairly normal). There's an overview of Haxe features here: http://haxe.org/documentation/introduction/language-features...
Haxe is a really good language. It's dynamic, reflective language with static type system with local type inference. It supports GADTs and pattern matching, along with the usual exhaustiveness checks. It allows for adding methods to a class from outside (a `using` keyword). It has hygienic macros similar to those of Dylan, Elixir or Sweet.js. It's type system gives you control over variance of types, which is really nice (OCaml and Scala do this too).
I think Haxe is a pretty solid language which works well for general purpose apps (from command line utilities to games) and it excels at multi-platform development. This includes backend and frontend development in web dev - with Haxe you not only can share your code between platforms (browser and node), but you also have a choice of compile target, so you can compile the same set of functions to JavaScript or Flash on the frontend and to C++ or PHP on the backend. And you can easilly switch from one target to another, for example I used the default neko target in development (blazing fast compilation) and C++ target for running on the remote server.
IMO Haxe is something very, very different to Typescript, and is a lot more powerful.
For instance, Haxe is great for web applications too -- one of it's chief draws is that you can share the same code on the front end and the back end, but target whichever language is best for that. JS on the front, PHP/NodeJS/Neko/Etc/ on the back.
UFront is just one great example: http://ufront.net/
As for other multimedia frameworks, here's my best attempt at an exhaustive list:
OpenFL - http://www.openfl.org
SnowKit - http://snowkit.org/
Kha - http://tech.ktxsoftware.com/
NME - https://github.com/haxenme/nme
Flambe - http://getflambe.com/
HEAPS - https://github.com/ncannasse/heaps
And things built on top of those:
HaxeFlixel - http://haxeflixel.com/
HaxePunk - http://haxepunk.com/
Luxe Engine - http://luxeengine.com/docs/
Away3D - https://github.com/away3d/away3d-core-openfl
HaxeUI - http://haxeui.org/
KhaPunk - https://bitbucket.org/stalei/khapunk
The differences explored in the article are borderline 'religious' reasons.
Why Typescript? Simple: VSCode. One of the things that Microsoft does best is IDEs/editors and the Typescript experience in VSCode (and VIM and what-have-you) is no exception.
EDIT: How has Haxe as a language escaped popular notice for so long?
- Language barrier (Since Haxe docs are first and foremost handled by europeans like me, I know English natives always find it a bit ghetto when they feel the writer isn't a native, but there is very little we can do about it)
- It's not as easy to use as it seems, though OpenFL made it a bit easier.
- Backward compatibility breaks between versions, I'm sorry but a language designer should never do that. I know it's tough to get things right on the first iteration,but v2 libs not working in v3 can slow down a language adoption. We've seen this countless times. It only piss off early adopters.
- Maybe too focused on Flash at first ( But the C++ and JS targets work quite well, in fact, both Android and IOS targets use C++ ).
- written in OCAML... makes it more difficult for people to contribute to the core.
I'd say wait a few more years until the stuff is mature.
EDIT: if you are writing a game it is a no brainer. Your app will run in the browser with JS, Flash and natively on Ios and Android with a single codebase and very very little tweaking.
Aside from that, it has a longer learning curve than TS. This article does a great job of outlining some of the differences.
EDIT: My guess would be that it was originally too focused in its use case as an ActionScript replacement for Flash. In current times, I would say that it has made the same mistake that everything other than TypeScript has: It tries to "fix" JavaScript / ECMAScript. That means learning yet another slightly-different thing, and also porting if it's not a new project. TypeScript has picked up a lot of momentum by taking the superset approach, allowing progressive enhancement of existing codebases. Just start throwing your JavaScript into the TypeScript compiler and you're done.
I should have specified that the above is the reason I would choose TypeScript over Haxe now. There's a lot of times when I will prototype a project in vanilla JavaScript, then set up the TypeScript build infrastructure and start enhancing.
- it didn't easily integrate with existing JS code/libraries
- small community
- low resources (compiler bugs existed and weren't quickly fixed)
The community was a dealbreaker really. Lots of JS libraries already have TS type definitions so it's easy to get started, and TS keeps up-to-date with new JS features.
I prefered the Haxe typesystem, but it didn't really make business sense to keep using it.
They'll probably fix this issue sooner rather than later but in the meanwhile it's a critical issue.
declare var Chart: any;
atop your file, and you can use it the same way you would in JS: without type info. No need to create any type definitions.Or do you mean something different?
Are you talking about what's described here: https://github.com/Microsoft/TypeScript/issues/2242
I just did a small typescript prototype and used the import syntax there. It might have been your typescript version as 1.5 recently came out (and I was using the 1.5 beta 2).
The hardest part is what you described at the start. If it doesn't have a type definition it's hard. DefinitelyTyped helps a lot (https://github.com/DefinitelyTyped/tsd)
I had to create a type definition for something that wasn't there. It was annoying because I had to make the equivalent of a header file before I could use a library.
it doesn't really, you basically need to write definitions files too with Haxe, just like Typescript. Or you loose 'type-safety', just like TS.
TS is off course closer to Javascript.
In the latter case, Typescript gives you some typing for free whereas Haxe doesn't.
And... not having a large company like MS backing it doesn't help it out any.
If anyone browsing the comments section is interested in a familiar-ish, statically typed and fairly powerful language that cross compiles to a huge range of back-ends and platforms, take a couple of minutes to visit haxe.org. It's worth the time.
Simple really - other languages, framework, and SDKs have filled the programming needs of people. I've found most source-to-source compilers to either be completely broken, too complicated to use, or not enough features (I've seen a number of Python to C compilers started and never even close to finished). I discovered Haxe many years ago when I had the idea for my own source-to-source compiler (and created my own lexer, parser, compiler, and virtual machine in C++).
I personally haven't used Haxe yet but I found it's documentation to be pretty good and it seems to have good reviews.
HLA [1] might also be interesting to you.
This has made the language a hard sell in its first decade. Lots of people have passed through, made something amazing, and then wandered off. The compiler has always been solid, but the rest of the ecosystem regularly encounters missing pieces. A "full-stack" mentality is nearly a must to ship a project in Haxe.
But since it's made it this far, it's only likely to keep improving from here. After all, "prevent lock-in" and "reduce portability costs" are powerful selling points.
I wonder if that guy is still at the helm.
Algebraic data types (and pattern matching) are definitely features that should be present in every language - the difference of modeling things without and with them is like night and day.
TypeScript's type system is indeed more forgiving, but mostly because the language is designed for migrating existing JS codebases to it. You can then tighten the grip significantly by adding `--noImplicitAny`. The most unfortunate TS unsoundness issue at the moment is that null/undefined are acceptable values for all types - I really wish they'd fix that...
What are the options for JS FFI in Haxe? Is there something less awkward to use (perhaps a more user friendly FFI library) than http://old.haxe.org/doc/advanced/magic#javascript-magic ?
-
Side note: automatic semicolon insertion was not a huge mistake, and Douglas Crockford saying it was doesn't make it so. If you follow 2 simple rules, you wont need any semicolons:
1) Dont put a new line between `return`/`throw`, and the returned/thrown expression (newlines inside the expression are fine)
2) Prepend `;` to a line starting with `(`
Crockford had a minifier bug related to #2 and solved someone else's problem with #1 then declared a rule to always use semicolons (which doesn't even help with #1)
1) Use a semicolon.
2) There is no rule 2.
EDIT: This may seem flippant but the point is that humans make mistakes and the more rules you have to obey, the more mistakes they will make. Especially beginners.
ASI (automatic semicolon insertion) and double-equals (weak comparison vs triple-equals strict comparison) aren't bad because they don't work, they are bad because they allow for unnecessary mistakes in return for a minimal reduction of characters you need to type.
Despite all the rationalizations, the primary reason some programmers prefer to rely on ASI is purely aesthetics. That's okay, but there's no point in trying to construct artificial arguments to defend that preference.
If a future version of the language somehow manages to eliminate the need for those rules, I'll be the last person to tell you to stick to your semicolons. Until then, it's still a voluntary handicap.
return
{
property: value
};
(Whats the value returned? Its `undefined`)Therefore, "Use a semicolon" is insufficient. Or rather, its about as sufficient as "Don't start a line with (".
Which means that the rule(s) for using semicolons are no more complex than the rules for not using them.
This is precisely why "follow these simple rules" is not enough. I believe that us programmers would really benefit if we stopped following and perpetuating best practices without understanding (and explaining) the reasons behind them very throughly.
If you want less cognitive overload, use a language with less warts, or a language with a type system. Lint-like rules that don't come with a reason are useless and result in a false sense of security
(full-disclosure...my project)
Mirror here: https://github.com/andyli/blog/blob/master/content/posts/201...
EDIT: Looks like it's back up.
metadata: http://haxe.org/manual/lf-metadata.html
The project that made me see its potential was "Haxe-WavPack-Decoder", an audio decoder for the WavPack file format. It targets Neko, C++, C#, Java and Javascript. Imagine using Haxe to write reference implementations for file formats (or anything, really), then spitting out implementations for any other target language, so you could include it in a project using any runtime of your choosing.
The problems I see are:
* The language itself is not a high-level wrapper for each platform/target, so you still need to write different code for each platform. (OpenFL/Lime does a great job at handling this for you for games)
* The compiled output might have surprising runtime characteristics. For example, I tried writing an audio rendering app where I targeted C++, and had a naive two-dimensional array (a Vector of Vectors of Floats). When I tried retrieving an inner array, it would attempt to cast the array and its entire contents. This happened every time the array was accessed, and it was accessed multiple times per second. When I flattened the arrays to a single array and used a calculated index, it reduced the processing time from ~30mins to ~5mins.
* You can't necessarily make use of each target language's strengths. For example, I think the Java target does not support annotations.
* If you want to make use of platform libs/tech, you'll need to define externs for each lib. (There's some efforts to use a TypeScript->Haxe converter to convert all of the DefinitelyTyped definitions to externs, so the JS target is looking promising.)
* It seems like a lot of developers come from a Flash/ActionScript background, so there's lots of ports of AS libs with documentation that just says "See the AS lib documentation". This is not helpful for general developers.
* Due to having so many use-cases, it's very hard to share knowledge for "Haxe" - are you looking for info on Haxe for games on desktop, or Haxe for games on HTML5, or Haxe for webapps on PHP, or Haxe for webapps on NodeJS...? This is a tribute to its versatility, but it means the developer mindshare gets splintered into separate tribes.
* Due to targeting other languages, you kind of have to be an expert in that language/platform already, which means you need to translate from the target language to Haxe in your head.
* Since macros can extend the language to do anything else, libraries will splinter based on capabilities and implementations of those capabilities. Some libraries might use an "Optional" macro, some might use "Maybe", and they'll do roughly the same thing but be incompatible.
* I believe libraries written in Haxe can only be distributed as source code, limiting commercial investment in developing libs. (Although, JS also has this problem but doesn't seem to suffered.)
* Still has nulls. :( It does make some efforts to make developers treat nullable values differently, but it seems inconsistent (and probably dependent on target).