10 Languages That Compile to JavaScript — SitePoint

August 22, 2017 0 Comments

10 Languages That Compile to JavaScript — SitePoint

 

 

Modern applications have different requirements than simple websites. But the browser is a platform with a (mostly) fixed set of technologies available, and JavaScript remains as the core language for web applications; any application that needs to run in the browser has to be implemented in that language.

We all know that JavaScript is not the best language for every task, and when comes to complex applications, it might fall short. To avoid this problem, several new languages and transpilers of existing ones have been created, all of them producing code that can work in the browser without writing any line of JavaScript and without thinking about the limitations of the language.

This article includes a list of ten interesting languages that can be transpiled to JavaScript to be executed in the browser or on a platform like Node.js.

Dart

Dart is a classical, object-oriented language where everything is an object and any object is an instance of a class (objects can act as functions too.) It is specially made to build applications for browsers, servers, and mobile devices. It is maintained by Google and is the language that powers the next generation AdWords UI, the most important product of Google regarding revenue, which is in itself a proof of its power at scale.

The language can be translated to JavaScript to be used in a browser, or be directly interpreted by the Dart VM, which allows you to build server applications too. Mobile applications can be made using the Flutter SDK.

Complex applications also require a mature set of libraries and language features specially designed for the task, and Dart includes all of this. An example of a popular library is AngularDart, a version of Angular for Dart.

It allows you to write type-safe code without being too intrusive; you can write types, but you are not required to do so since they can be inferred. This allows for rapid prototyping without having to overthink the details, but once you have something working, you can add types to make it more robust.

Regarding concurrent programming in the VM, instead of shared-memory threads (Dart is single-threaded), Dart uses what they call Isolates, with their own memory heap, where communication is achieved using messages. In the browser, the story is a little different: instead of creating new isolates, you create new Workers.

// Example extracted from dartlang.org import 'dart:async'; import 'dart:math' show Random; main() async { print('Compute π using the Monte Carlo method.'); await for (var estimate in computePi()) { print('π ≅ $estimate'); } } /// Generates a stream of increasingly accurate estimates of π. Stream<double> computePi({int batch: 1000000}) async* { var total = 0; var count = 0; while (true) { var points = generateRandom().take(batch); var inside = points.where((p) => p.isInsideUnitCircle); total += batch; count += inside.length; var ratio = count / total; // Area of a circle is A = π⋅r², therefore π = A/r². // So, when given random points with x ∈ <0,1>, // y ∈ <0,1>, the ratio of those inside a unit circle // should approach π / 4. Therefore, the value of π // should be: yield ratio * 4; } } Iterable<Point> generateRandom([int seed]) sync* { final random = new Random(seed); while (true) { yield new Point(random.nextDouble(), random.nextDouble()); } } class Point { final double x, y; const Point(this.x, this.y); bool get isInsideUnitCircle => x * x + y * y <= 1; } 

Get started with Dart

TypeScript

TypeScript is a superset of JavaScript; a valid JavaScript program is also valid TypeScript but adding static typing. The compiler can also work as a transpiler from ES2015+ to current implementations, so you always get the latest features.

Unlike many other languages, TypeScript keeps the spirit of JavaScript intact, only adding features to improve the soundness of the code. These are type annotations and other type-related functionality that makes writing JavaScript more pleasant, thanks to the enabling of specialized tools like static analyzers and other tools to aid in the refactoring process. Also, the addition of types improve the interfaces between the different components of your applications.

Type inference is supported, so you don’t have to write all the types from the beginning. You can write quick solutions, and then add all the types to get confident about your code.

TypeScript also has support for advanced types, like intersection types, union types, type aliases, discriminated unions and type guards. You can check out all these in the Advanced Types page in the TypeScript Documentation site.

JSX is also supported by adding the React typings if you use React.

class Person { private name: string; private age: number; private salary: number; constructor(name: string, age: number, salary: number) { this.name = name; this.age = age; this.salary = salary; } toString(): string { return `${this.name} (${this.age}) (${this.salary})`; } } 

Recommended Courses

Elm

Elm is a purely functional programming language that compiles to JS, HTML, and CSS. You can build a complete site with just Elm, making it a great alternative to JavaScript frameworks like React. The applications that you build with it automatically use a virtual DOM library, making it very fast. One big plus is the built-in architecture that makes you forget about data-flow and focus on data declaration and logic instead.

In Elm, all functions are pure, which means that they will always return the same output for a given input. They can’t do anything else unless you specify it. For example, to access a remote API you would create command functions to communicate with the external world, and subscriptions to listen for responses. Another point for purity is that values are immutable; when you need something, you create new values, instead of modifying them.*

The adoption of Elm can be gradual; it is possible to communicate with JavaScript and other libraries using ports. Although Elm hasn’t reached version 1 yet, it is being used for complex and large applications, making it a feasible solution for complex applications.

One of the most attractive features of Elm is the beginner-friendly compiler, which, instead of producing hard-to-read messages, generates code that helps you to fix your code. If you are learning the language, the compiler itself can be of big help.

module Main exposing (..) import Html exposing (..) -- MAIN main : Program Never Model Msg main = Html.program { init = init , update = update , view = view , subscriptions = subscriptions } -- INIT type alias Model = String init : ( Model, Cmd Msg ) init = ( "Hello World!", Cmd.none ) -- UPDATE type Msg = DoNothing update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of DoNothing -> ( model, Cmd.none ) -- VIEW view : Model -> Html Msg view model = div [] [text model] -- SUBSCRIPTIONS subscriptions : Model -> Sub Msg subscriptions model = Sub.none 

Get Started with Elm

PureScript

PureScript is a purely functional and strongly-typed programming language, created by Phil Freeman. It aims to provide strong compatibility with available JavaScript libraries, similar to Haskell in spirit, but keeping JavaScript at its core.

A strong point for PureScript is its minimalism. It doesn’t include any libraries for functionality that would be considered essential in other languages. For example, instead of including generators and promises in the compiler itself, you can use specific libraries for the task. You can choose the implementation you want for the feature you need, this allows a highly efficient and personalized experience when using PureScript, while keeping the generated code as small as possible.

Another distinctive feature of its compiler is the ability to make clean and readable code while maintaining compatibility with JavaScript, both concerning libraries and tools.

Like other languages, PureScript has its own build tool called Pulp, which can be compared to Gulp, but for projects written in this language.

Regarding the type system—unlike Elm, which is the other ML-like language—PureScript has support for advanced type features like higher-kinded types and type classes, which are taken from Haskell, allowing the creation of sophisticated abstractions.

module Main where import Prelude import Data.Foldable (fold) import TryPureScript main = render $ fold [ h1 (text "Try PureScript!") , p (text "Try out the examples below, or create your own!") , h2 (text "Examples") , list (map fromExample examples) ] where fromExample { title, gist } = link ("?gist=" <> gist) (text title) examples = [ { title: "Algebraic Data Types" , gist: "37c3c97f47a43f20c548" } , { title: "Loops" , gist: "cfdabdcd085d4ac3dc46" } , { title: "Operators" , gist: "3044550f29a7c5d3d0d0" } ] 

Get Started with PureScript

CoffeeScript

CoffeeScript is a language that aims to expose the good parts of JavaScript while providing a cleaner syntax and keeping the semantics in place. Although the popularity of the language has been waning in recent years, it’s changing direction and is now getting a new major version providing support for ES2015+ features.

The code that you write in CoffeeScript is directly translated to readable JavaScript code and maintains compatibility with existing libraries. Starting from version 2, the compiler will produce code compatible with the latest versions of ECMAScript, for example, every time you use a class, you will get a class in JavaScript. Also, if you use React, there is good news: JSX is compatible with CoffeeScript.

A very distinctive feature of the compiler is the ability to process code written in the literate style, where instead of making emphasis in the code and have comments as an extra, you write comments in the first place, and the code only occasionally appears. This style of programming was introduced by Donald Knuth, making a code file very similar to a technical article.

Unlike the other languages, CoffeeScript code can be interpreted directly in the browser using a library. So if you want to create a quick test, you can write your code in text/coffeescript script tags, and include the compiler, which will translate the code to JavaScript on the fly.

# Assignment: number = 42 opposite = true # Conditions: number = -42 if opposite # Functions: square = (x) -> x * x # Arrays: list = [1, 2, 3, 4, 5] # Objects: math = root: Math.sqrt square: square cube: (x) -> x * square x # Splats: race = (winner, runners...) -> print winner, runners # Existence: alert "I knew it!" if elvis? # Array comprehensions: cubes = (math.cube num for num in list) 

Get Started with CoffeeScript 2

ClojureScript

ClojureScript is a compiler that translates the Clojure programming language to JavaScript. It is a general-purpose, functional language with dynamic typing and support for immutable data structures.

It is the only one from this list that belongs to the Lisp family of programming languages and, naturally, it shares a lot of the features. For example, the code can be treated as data, and a macro system is available, making meta-programming techniques possible. Unlike other Lisps, Clojure has support for immutable data structures, making the management of side-effects easier.

The syntax can look intimidating for newcomers for its use of parenthesis, but it has profound reasons to be that way and you will certainly appreciate it in the long run. That minimalism in the syntax and its syntactic abstraction capabilities make Lisp a powerful tool for solving problems that require high levels of abstraction.

Although Clojure is mainly a functional language, it isn’t pure like PureScript or Elm; side-effects can still happen, but other functional features are still present.

ClojureScript uses Google Closure for code optimization and also has compatibility with existing JavaScript libraries.

; Extracted from https://github.com/clojure/clojurescript/blob/master/samples/dom/src/dom/test.cljs (ns dom.test (:require [clojure.browser.event :as event] [clojure.browser.dom :as dom])) (defn log [& args] (.log js/console (apply pr-str args))) (defn log-obj [obj] (.log js/console obj)) (defn log-listener-count [] (log "listener count: " (event/total-listener-count))) (def source (dom/get-element "source")) (def destination (dom/get-element "destination")) (dom/append source (dom/element "Testing me ") (dom/element "out!")) (def success-count (atom 0)) (log-listener-count) (event/listen source :click (fn [e] (let [i (swap! success-count inc) e (dom/element :li {:id "testing" :class "test me out please"} "It worked!")] (log-obj e) (log i) (dom/append destination e)))) (log-obj (dom/element "Text node")) (log-obj (dom/element :li)) (log-obj (dom/element :li {:class "foo"})) (log-obj (dom/element :li {:class "bar"} "text node")) (log-obj (dom/element [:ul [:li :li :li]])) (log-obj (dom/element :ul [:li :li :li])) (log-obj (dom/element :li {} [:ul {} [:li :li :li]])) (log-obj (dom/element [:li {:class "baz"} [:li {:class "quux"}]])) (log-obj source) (log-listener-count) 

Get Started with ClojureScript

Scala.js

Scala.js is a compiler that translates the Scala programming language to JavaScript. Scala is a language that aims to merge the ideas from object-oriented and functional programming into one language to create a powerful tool that is also easy to adopt.

As a strongly typed language, you get the benefits of a flexible type system with partial type inference. Most values can be inferred, but function parameters still require explicit type annotations.

Although many common object-oriented patterns are supported (e.g. every value is an object and operations are method calls), you also get functional features like support for first-class functions and immutable data structures.

One of the special advantages of Scala.js is that you can start with a familiar, object-oriented approach and move to a more functional one as you need and at your own speed without having to do a lot of work. Also, existing JavaScript code and libraries are compatible with your Scala code.

Beginner Scala developers will find the language not very different from JavaScript, compare the following equivalent code:

// JavaScript var xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.twitter.com/1.1/search/" + "tweets.json?q=%23scalajs" ); xhr.onload = (e) => { if (xhr.status === 200) { var r = JSON.parse(xhr.responseText); $("#tweets").html(parseTweets(r)); } }; xhr.send(); 
// Scala.js val xhr = new XMLHttpRequest() xhr.open("GET", "https://api.twitter.com/1.1/search/" + "tweets.json?q=%23scalajs" ) xhr.onload = { (e: Event) => if (xhr.status == 200) { val r = JSON.parse(xhr.responseText) $("#tweets").html(parseTweets(r)) } } xhr.send() 

Get Started with Scala.js

Reason

Reason is a language created and maintained by Facebook that offers a new syntax for the OCaml compiler, and the code can be translated to both JavaScript and native code.

Being part of the ML family and a functional language itself, it naturally offers a powerful but flexible type system with inference, algebraic data types and pattern matching. It also has support for immutable data types and parametric polymorphism (also known as generics in other languages) but, as in OCaml, support for object-oriented programming is available as well.

The use of existing JavaScript libraries is possible with bucklescript bindings. You can also mix in JavaScript alongside your Reason code. The inserted JavaScript code won’t be strictly checked, but it works fine for quick fixes or prototypes.

If you are a React developer, bindings are available and the language also has support for JSX.

/* A type variant being pattern matched */ let possiblyNullValue1 = None; let possiblyNullValue2 = Some "Hello@"; switch possiblyNullValue2 { | None => print_endline "Nothing to see here." | Some message => print_endline message }; /* Parametrized types */ type universityStudent = {gpa: float}; type response 'studentType = {status: int, student: 'studentType}; let result: response universityStudent = fetchDataFromServer (); /* A simple typed object */ type payload = Js.t {. name: string, age: int }; let obj1: payload = {"name": "John", "age": 30}; 

Get Started with Reason

Haxe

Haxe is a multi-paradigm programming language, and its compiler can produce both binaries and source code in other languages.

Although Haxe provides a strict type system with support for type inference, it can also work as a dynamic language if the target language supports it. In the same way, it provides support for a variety of programming styles like object-oriented, generic, and functional.

When you write Haxe code, you can target several platforms and languages for compilation without having to make considerable changes. Target-specific code blocks are also available.

You can write both back-ends and front-ends in Haxe with the same code and achieve communication using Haxe Remoting, for both synchronous and asynchronous connections.

As expected, Haxe code is compatible with existing libraries but also provides a mature standard library.

// Example extracted from http://code.haxe.org extern class Database { function new(); function getProperty<T>(property:Property<T>):T; function setProperty<T>(property:Property<T>, value:T):Void; } abstract Property<T>(String) { public inline function new(name) { this = name; } } class Main { static inline var PLAYER_NAME = new Property<String>("playerName"); static inline var PLAYER_LEVEL = new Property<Int>("playerLevel"); static function main() { var db = new Database(); var playerName = db.getProperty(PLAYER_NAME); trace(playerName.toUpperCase()); db.setProperty(PLAYER_LEVEL, 1); } } 

Get Started with Haxe

Nim

Nim is a statically-typed, multi-paradigm programming language with minimalist and whitespace-sensitive syntax that compiles to C, C++, and JavaScript.

The language itself is very small, but its meta-programming capabilities make it attractive to implement features by yourself that you might find built-in to other languages. The building blocks for this are macros, templates, and generics, and with them you can implement things from simple features to different paradigms. This makes Nim an extremely versatile language that can be adapted to your needs, in the spirit of Lisp.

The syntactic abstraction features of Nim allow you to adapt the language to your problems, making true DSLs possible. If you have specialized tasks to solve, you can get a higher level of expressiveness.

# Reverse a string proc reverse(s: string): string = result = "" for i in countdown(high(s), 0): result.add s[i] var str1 = "Reverse This!" echo "Reversed: ", reverse(str1) # Using templates template genType(name, fieldname: expr, fieldtype: typedesc) = type name = object fieldname: fieldtype genType(Test, foo, int) var x = Test(foo: 4566) echo(x.foo) # 4566 

Get Started with Nim

Conclusion

If JavaScript is not your favorite language, you can still create web applications without having to suffer the shortcomings of the technology. The options available to create those applications can fill a wide spectrum of taste, from the purely functional languages, like PureScript, to the object-oriented ones, like Dart. And if you want something more than a one-to-one language translation, you have options like Elm that provide you with tools like a virtual DOM and a built-in architecture.

Have you tried any of the languages from this article or do you have one to recommend? Let us know in the comments!


Tag cloud