Jump to content

Languages that compile into JS


Tooon
 Share

Recommended Posts

I was wondering what opinion everyone has on languages that compile into JS. Is it worth using them for html5 game development? (I just got into HTML5) Which do you personally use? I've been looking into them, but honestly, I don't really see the benefit. Anyone who can explain them and suggest one would be appreciated. (There are just so many!)

 

 

Link to comment
Share on other sites

IMO, you're better off gaining experience by coding in plain JS first. Once you have that experience you'll be in a much better position to weigh the pros and cons of switching to a different language, and which one to choose. As JS evolves it's picking up some of the benefits originally provided by those other languages anyway. I briefly started out with TypeScript before switching to vanilla JS. I'm glad I switched to JS early because now I can look back and see my original reasons for wanting to start with TypeScript were somewhat misguided.

Link to comment
Share on other sites

I have experience with both Typescript and Haxe.  Some subjective comments as I see them:

Typescript has an excellent website to learn the reasons why typing is beneficial, and how to do it.  The language is well featured, but the tooling (in my opinion) can be slow and fussy.  Setting up configuration files and compiler watches is not much fun, and because TS is a superset of JS it means some anti-patterns can sneak into a project's codebase.  TS does not help with all JS legacy issues like this. bind. and readonly properties but does offer some ES6 features ahead of time (let, const). 

Haxe improves on performance and ease of build but is heavy reading (all-things-to-all-people causes confusion and rejection) and can look ugly at first glance.  It provides automated assistance for most of the JS syntax issues and offers additional targets for the project's codebase (if needed).  However I long ago stopped trying to convert people to Haxe's awesomeness because it is almost impenetrable to a newcomer .... instead I selfishly continue to choose it for every project I can.

 

 

Link to comment
Share on other sites

Depends largely on the project, although BobF's advice of learning the core language first is golden.

Stuff like Haxe and Typescript, which add some degree of type safety to the build (I don't think either has a runtime variant, which is just as important for JS) can be really useful for teams on large code bases but is largely useless and irrelevant for small teams (or solo) on smaller projects (with the notable exception that some people simply prefer strong typing but still want the power and flexibility of the web). Not worth the overhead, as mentioned, newer JS versions add many features (it wont do typing, because, well, JS is loosely typed). Flow (and flowcheck) are interesting as rather than break the core language to create a new one they simply add features to JS, bit of overhead again but if you want some typing then they are useful and flowcheck has a runtime (obvs just for dev builds) solution that will check the type of a variable during runtime, which is when the really nasty bugs would present themselves anyway. I've used it before and its a nice procedure but its still not worth the effort for smaller projects.

Other stuff like Dart is fun, and adds some stuff to JS but the same holds true, I really dont see the point. If you're comfortable writing in C then using LLVM as an intermediary step to JS is all well and good, but, honestly, is it worth it for your project? Does it need to additionally compile to ASM for WASM?

The only one that really catches my attention is Elm. Totally and utterly different from JS, it simply uses JS as a compile target to get all of the advantages surrounding JS (i.e. the browser). Elm is, quite simply, wonderful. As concise and beautiful as Haskell. But only if you're into that sort of thing. A useful discipline to learn though for sure.

Link to comment
Share on other sites

I don't see any reason not to choose Haxe over JS. Haxe gives you native performance on most platforms. Maybe it doesn't compile to the most performant JS you would get if you just used JS itself, but since you're using the GPU, who cares...

Link to comment
Share on other sites

 

18 hours ago, BobF said:

IMO, you're better off gaining experience by coding in plain JS first.

+1

Here is an interesting answer from stackoverflow about this: http://stackoverflow.com/a/14660852/6599880

 

 

13 minutes ago, mattstyles said:

Stuff like Haxe and Typescript, which add some degree of type safety to the build (I don't think either has a runtime variant, which is just as important for JS) can be really useful for teams on large code bases but is largely useless and irrelevant for small teams (or solo) on smaller projects.

I don't agree here, I use C# with Visual Studio and it gives me compile-time type checking, global rename(reliable one; advanced JS IDE-s like Webstorm also have global rename but you can't trust them completely - because JS... and inability to rename quickly subconsciously discourages refactoring), better auto-completion and parameter info. I really miss these in JS.

Link to comment
Share on other sites

2 hours ago, Fatalist said:

I don't agree here, I use C# with Visual Studio and it gives me compile-time type checking, global rename(reliable one; advanced JS IDE-s like Webstorm also have global rename but you can't trust them completely - because JS... and inability to rename quickly subconsciously discourages refactoring), better auto-completion and parameter info. I really miss these in JS.

I agree with you, its not totally irrelevant, purely dependent on the individual, I'll update my response, and I hadn't considered that strong typing will give you more auto-completion info if you need that sort of thing.

Link to comment
Share on other sites

5 hours ago, Fatalist said:

I use C# with Visual Studio and it gives me compile-time type checking, global rename(reliable one; advanced JS IDE-s like Webstorm also have global rename but you can't trust them completely - because JS... and inability to rename quickly subconsciously discourages refactoring), better auto-completion and parameter info. I really miss these in JS.

WebStorm gives you all of that and more, which is why I ended up choosing it for my coding. One reason I thought I would need TypeScript is because I really prefer finding my bugs at compile time, rather than later. But WebStorm's as-you-type linting seems to find most (although not all!) of my typical syntax errors, so that has satisfied my need. As you say, a little care is needed when using the refactor feature, but I find it very useful.

Link to comment
Share on other sites

@Fatalist That stack overflow chart is interesting but it omits the other things a pure javascript approach must learn to be on equal footing - e.g. dynamic workarounds and cleanups used to overcome absences in the underlying language.  Naturally the transpilers can only achieve functions already possible in pure javascript, but to have them magically concealed from the code we look at is often crucial to smart and expedient progress.  Yes, it sure helps to understand all aspects of the chain, but it's not crucial - we wouldn't make knowledge of assembly a dependency of learning c++ by comparison.  So my opinion is there is more to learn on the "Choose JS" column.

@Milton There are scenarios where Haxe can be more performant than plain javascript (and Typescript) - but it depends on the individual writing it.  For example automatically binding function scope can be beneficial for runtime performance and writing the code.  Haxe does it by default.  It can be done in javascript and Typescript too, but such manual code requires: the knowledge of the issue, a design pattern to overcome the issue, code review to enforce the pattern.

Link to comment
Share on other sites

16 hours ago, b10b said:

For example automatically binding function scope can be beneficial for runtime performance and writing the code.  Haxe does it by default.  It can be done in javascript and Typescript too, but such manual code requires: the knowledge of the issue, a design pattern to overcome the issue, code review to enforce the pattern.

I'm not saying you're wrong about Haxe, certainly these transpilers are optimised well and the patterns they allow can often be awkward to code in vanilla JS, but, your example is dreadful. Mutating scope is a core JS technique, and using .bind is about as simple as it can get, also, that scope change is less performant that simply invoking a function, if Haxe does it all the time then it will be doing it unnecessarily, as I'd expect a junior JS person to be able to use .bind that means that Haxe (just in this case) is slower than a novice programmer, and it won't be ergonomic either as adding .bind is simple (not to mention having total unsurprising control over scope is more flexible).

Could well be better optimised in many other situations though, particularly as it eleviates the programmer from the chore of trying to optimise some bits.

Link to comment
Share on other sites

Many good points have been mentioned already. If you have a language that compiles to JS without knowing JS, you might run into big problems debugging; you can never be sure, who's to blame for bugs - you, your X to JS compiler, JS, or the library you used. So even if you don't like JS (and there's lot of reasons to dislike it, especially if you're familiar with other languages), you need to know it first.

 

Something that has not been mentioned yet is ClojureScript. I do the terribly evil deed of writing games in ClojureScript, and it does work really well for me. The reasons behind this choice are as follows:

JS's take on var, this, and even inheritance/prototyping is very confusing to beginning developers; it took me longer than in any other language to be able to securely do basic OOP due to these quirks. I could only really understand them once I got serious with functional programming. I think, JS pretends to be OO, while it happily mixes FP and OOP concepts.

Another thing that makes JS development tricky is, how quickly one can get lost in the depths of callbacks creating callbacks that mutate objects and create callbacks and so on, commonly refered to as "callback hell". Here ClojureScript really shines. I can write a game loop that keeps an immutable game state and reacts to callback events once and in a controlled way, updating game state predictably (and even with the possibility to go back in time/undo for free).

Live developing running games using browser-REPL gives you the ability to 1) immediately test and modify behavior (like you could from the browser console in plain JS, too), while 2) you still have a compiling-like step after each line of code you send to the game, detecting syntax errors.

The CLJS syntax is (arguably) simpler than pure JS's (and really much simpler than Java's), and you can do the same task in much less lines of codes; plus if you really need to create a native desktop/Android application of your project, you only need to modify the input/output routines of your web game and compile it to (Android-)Java.

There's also downsides, of course. Purely functional programming may sound quite esotheric to OOP/procedural programmers at first; compiling CLJS apps pulls in the whole goog codebase (although optimization removes much of it in production), and thus web loading times are longer than pure JS games. Very complex games may run less performant due to an additional layer of function calls wrapping native library methods (though that never was notably at my projects yet).

 

At the end of the day, you should not go and find "the best language" and "the best toolkit". Choose a language and toolkit that allow you to reach your goal in reasonable time with the least headache. Look at tutorials for the type of app/game you want to create and decide which one is best to follow for you. You learn programming by everything you create, and hitting walls and problems in one scenario helps you understand why other languages/toolkit do it differently. Programming itself does not depend on specific languages (although there's "industry standards" - but you could just compile to, say JS, when your're done, right? ;) ). You will change preferred languages. You will change preferred toolkits. You will change project setups, programming paradigms, application targets and so on. Just stay curious and try.

 

That's just my biased two pence :)

Link to comment
Share on other sites

@mattstyles perhaps I don't appreciate how scope constantly mutating (with JS) is always an advantage.  From my understanding Haxe assumes we intend to bind a method to the original body, and (given an anonymous function) creates the binding for us.  The option to bind elsewhere (which I imagine is not type safe?) also exists but is not the default.  When combined with the option to skip the often superfluous "this" keyword the written code can be half the length of equivalent JS.  Apologies if my terminology is not exactly correct, I am not the designer of the language, just a user who appreciates the elegance of the solution.

 

Link to comment
Share on other sites

@b10b check out how event listeners work, particularly DOM event listeners, for how mutative scope can be a huge advantage, even if you use a strict OOP methodology to create your project. Or check how jQuery makes use of it (I'm not a fan of jQuery at all, but how it mutates scope is critical for how it works, and for a long time it was an important library). Or how about code reuse? Mutative scope means that, at least potentially, functions can be reused in numerous ingenious places.

The JS language people had the perfect opportunity to revise the auto-binding mechanism when they introduced the class keyword, many libraries using a class-based architecture had already adopted auto method scope binding, they rejected for numerous very valid reasons, and those people are seriously smart, plus, they really consider every thing they do.

It might make more sense in the Haxe world, probably does, but its still a feature of JS that the custodians of the language were unwilling to part with and there was a good lobby for the other camp so its not like it wasn't discussed at length. The TC39 keeps detailed records of most correspondence, all publicly available if you fancy a deep dive. I can't pretend I can keep up with all they discuss, maybe you'll do better. Like I said, those guys and gals are all kinds of serious smart.

I'm all for removing features from things (see antoine de saint-exupéry) but JS scope mutation is a key language feature and an opt-in feature at that. If you don't want to make use of it, nothing is going to penalise you for ignoring solutions that use it, except, perhaps, the people funding your projects and the users of your projects.

Scope binding has nothing to do with type safety, statically typed languages include that just to try and stop devs from making silly, but easy, mistakes. JS has no static type checking, unless you run a process specifically for it, again, this is a language feature based around choosing to make it a loosely typed language. This feature allows some very elegant solutions to emerge, with the flip side being that JS is rife with footguns.

Haxe made those design choices for very good reasons and where it differentiates itself from JS it does so to improve its own use-cases, which is all any language can do really, its just that those design choices (at least, the ones you've mentioned) were not made for performance reasons.

 

Link to comment
Share on other sites

@mattstyles thank you, very informative as always.  Haxe issue 1193 (May 2013) suggests the design behind $bind included performance choices, and also that native bind (ES5) was not widely available - no benchmarks were provided, and perhaps this is outdated info today?  But I agree that its merits may lay in broader Haxe considerations (consistency across targets, and type referencing).  On the latter I am curious as to why you said "scope binding has nothing to do with type safety" - a function bound to a stranger could mutate the stranger's internal state in unexpected ways, some may be fun, but most won't be, so I'd air on the side of safety with the default being the safe(r) bind.  Thanks again for your insight.

 

Link to comment
Share on other sites

@b10b yeah, you're right, changing scope willy-nilly can be misused but type safety literally just refers to the types of the variables being manipulated. If you changed the scope and then tried to reference variables on `this` that were now inconsistent (i.e. `this.position` in one structure is an integer such as an array index, whereas `this.position` is an array of [x, y] for a sprite or something) then type safe languages would baulk at you that its expecting an integer and its being given an array. You can work this out statically (i.e at compile time) easily enough but JS is flexible so you'd need a process running all the time to do it at runtime (some languages do this, some rely on strong static checks to cover it), flowcheck is a module that does this and it isn't as slow as you might think (its generally fine for dev).

Yeah, compatibility was a problem in the past, IE9 was the first IE to support .bind, although a polyfill is fairly straight forward.

I've been working with Rust recently, that takes type safety to a whole new level. It has a special variable lifetime concept (amongst other things) which becomes super important, it can almost work out statically what every value will be for the entirety of the run time with the upshoot that if you get something to compile (not super easy!) then it becomes very hard to crash a program! 

Link to comment
Share on other sites

@mattstyles Rust sounds interesting, I'll add that to my reading list.  In respect of Haxe's bind advantage - you challenged me sufficiently for me to run some tests on my original claim :)  Test 1 was applying a fresh bind to a fresh object - results: Haxe's $bind was 1.6x faster on Chrome but ~20x slower on Firefox or IE.  Test 2 was (re)applying a fresh bind to a pooled object - results: Haxe's $bind was 16x faster on Chrome, 5x faster on Firefox but 0.85x as fast on IE.  The differences are because Haxe replaces native bind with a (cached?) closure automatically.  I suspect all the tests here are a world apart from any practical application.

 

Link to comment
Share on other sites

  • 2 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...