4

I am not really happy with JavaScript.

Here some weeping:

  • no set operations
  • inheritance not as simple as in Python
  • nested function definitions, callbacks, are hard to debug

Required features:

  • open source
  • must run in browser without extra plugin
  • I doubt anything else exists, at least with the support JS has. Fundamentally, browsers have since long ago "declared" JavaScript the defacto standard. Current browsers don't interpret any other language. The only "alternative" I can think of is VBScript running under Internet Explorer, which doesn't exists anywhere else. – Alejandro May 23 '17 at 14:29
  • @Alejandro AFAIK there are languages which "compile" to JS. But I have no clue about the state of the art. – guettli May 24 '17 at 8:08
3

The only language that can portably fill JavaScript's current target in browsers is JavaScript. Make sure you are using the newest ECMAScript standard (ES2016/2017) and use a transpiler such as BabelJS to output JS following an earlier standard if required.

If this isn't enough for you, other languages have the capability of compiling down to JavaScript.

TypeScript is a superset of JavaScript (this means all valid JS is valid TS). However, it introduces elements of Static Typing and other type and inheritance related abstractions over "standard JS" (following ES2016 syntax where it exists), allowing for a richer debug experience, and transpiles down to common JS that every browser supports. It's free and open source, backed by Microsoft and a favorite of Angular. Most popular IDEs have (a) plugin(s) available to make TypeScript development as simple as possible.

Kotlin is a JVM language originally designed as a better Java and recently adopted by Android as a native language. It also has first class support for a JS target (as of 1.1). If you really want to do true OOP, then this is probably one of the better options as Kotlin was first a Java derivative, and Java is (almost) purely OOP. Of course, Kotlin also supports more functional style code, which is considered more idiomatic in most cases and is gaining more and more popularity throughout the JS world. Kotlin is open source and developed by JetBrains, the creators of IntelliJ IDEA. Official plugins for development are available for IDEA and Eclipse, with community-driven plugins for most other IDEs.

Other languages exist which transpile to JavaScript. Hopefully, when WebAssembly becomes widely supported, most languages will be able to support the web as a compilation target.


As of December 2017, all major browsers have support for WebAssembly. C, C++, and Rust all have existing targets for WebAssembly using LLVM and/or EmScripten. WebAssembly is still young and there are still growing pains, but it is usable. See What languages can be compiled to web assembly (or wasm)? and Mawg's answer to this question for more information.

Additionally, I've used JS more since originally writing this answer. So long as you're writing modern JS using modern syntax, it's pretty good. With async/await, asynchronous code is a lot easier to handle, and spread/destructuring make certain things easier as well. JavaScript really is becoming pythonic.


It's January 2017, and that WebAssembly magic that I predicted is coming around. You still can't access web APIs seamlessly, but using the Parcel zero-configuration web application bundler, you can just import (simple) Rust fn in JS!

4

[Update to accepted answer, for the benefit of future readers] :

As @CAD97 prophesied, WebAssembly is now supported across all major browsers.

If you want to reduce the amount of JS that you code (you cannot elimnate it entirely), then Google for WebAssembly, if you can code in C, C++ or Rust.

Here's a very simple example from this tutorial :

Take the C code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <emscripten/emscripten.h>

int main(int argc, char ** argv) {
    printf("WebAssembly module loaded\n");
}

int EMSCRIPTEN_KEEPALIVE roll_dice() {
    srand ( time(NULL) );
    return rand() % 6 + 1;
}

compile it to WebAssembly with the command emcc dice-roll.c -s WASM=1 -O3 -o index.js

and invoke the WebAssembly of your C code in your HTML :

<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>WebAssembly Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>

    <!-- Include the JavaScript glue code. -->
    <!-- This will load the WebAssembly module and run its main. --> 
    <script src="index.js"></script>

  </body>
</html> 

It's early days yet for WebAssembly, but there are good tutorials around. And, apparently, we will soon be debugging that C code in the browser, just as we debug our JS today.

The one downside is that only numbers can be exchanged, so currently passing/returning objects & structures means writing some conversion code, but I am certain that there will very soon be some generic library functions to do so.

  • 1
    I've actually done a minimal amount of WebAssembly with Rust. It's.... an interesting ecosystem right now. Lots of growing pains. – CAD97 Dec 6 '17 at 5:06
  • 1
  • I am looking for some libraries to ease the translation of complex data types. In fact, I think that I will post a question asking for such later today. – Mawg Dec 6 '17 at 7:27
  • Done. See this question – Mawg Dec 6 '17 at 7:43
2

There is Brython, which lets you use Python inside web pages (with something like <script type="text/python">). Caveats:

  1. It suffers a performance penalty relative to doing the same thing in regular Python or plain JavaScript, especially at page load time.
  2. There are still occasional bugs.
  3. It's actually still JavaScript; Brython just compiles your Python to JavaScript. However, this is quite effectively hidden and it's possible to write your site code entirely in Brython without using any "raw" JavaScript.

Its advantages:

  1. It works without any special browser support. Unlike most other transpilers, it compiles to JavaScript on the fly. This means you can actually write Python code in a <script> tag instead of having to precompile your code to JavaScript in a separate step. (This is, however, why it's slow.)
  2. It is open source and development seems to be fairly active.
  3. Python is better than JavaScript in every way.
  • This looks very interesting. I will be investing some time in it; maybe a hello world project at least. You mention "a performance penalty" - do you have details? if not, I cold profile my project. But, since you say "especially at page load time", that mitigates my concern, as most of my SPAs consist of a series of user interactions, each leading to some AJAX and processing of the result. It would be good to be able to code much/most in Python, instead of JS. – Mawg Jan 11 '18 at 7:09
  • 1
    @Mawg: You can find more information if you poke around the Brython site and/or mailing list. One of the biggest costs is that (unless you try to get very clever) Brython has to load essentially the entire Python standard library (in JavaScript form) at page load time; this is a sizable amount of JS code that has to be transferred and run. In my experience there is a noticeable delay even when loading a page that just loads Brython but doesn't really do anything. Also, for your own code, Brython transpiles it to JavaScript on the fly (i.e., on every page load), which also takes time. – BrenBarn Jan 11 '18 at 7:30
  • 1
    (continued...) That said, I have written a small web app that used 100% Brython, no "real" JavaScript, and it's way more pleasant than writing in JS. Performance has also tended to improve slightly with newer versions of Brython. I'd suggest you play around and try doing some stuff and see if the performance issues are something you can live with for your use case. Overall Brython is definitely worth a look. – BrenBarn Jan 11 '18 at 7:34
2

[I think my existing answer is still useful, but I have encountered further information that encouraged me to make another answer.]

@CAD97 and @Mawg suggest WebAssembly as a potential target for replacing JavaScript in the future. However, this is not a goal of the project:

Is WebAssembly trying to replace JavaScript?

No! WebAssembly is designed to be a complement to, not replacement of, JavaScript. While WebAssembly will, over time, allow many languages to be compiled to the Web, JavaScript has an incredible amount of momentum and will remain the single, privileged (as described above) dynamic language of the Web. Furthermore, it is expected that JavaScript and WebAssembly will be used together in a number of configurations:

  • Whole, compiled C++ apps that leverage JavaScript to glue things together.
  • HTML/CSS/JavaScript UI around a main WebAssembly-controlled center canvas, allowing developers to leverage the power of web frameworks to build accessible, web-native-feeling experiences.
  • Mostly HTML/CSS/JavaScript app with a few high-performance WebAssembly modules (e.g., graphing, simulation, image/sound/video processing, visualization, animation, compression, etc., examples which we can already see in asm.js today) allowing developers to reuse popular WebAssembly libraries just like JavaScript libraries today.
  • When WebAssembly gains the ability to access garbage-collected objects 🦄, those objects will be shared with JavaScript, and not live in a walled-off world of their own.

WebAssembly is a companion to JavaScript. The intended use case is that libraries are written and compiled to WASM, and then called from JS. But given that you compare JS to Python in the OP, you might be interested to know that JavaScript is becoming pythonic!

Classes

Python:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return "({x}, {y})".format(x=self.x, y=self.y)

JavaScript:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString() {
        return `(${this.x}, ${this.y})`;
    }
}

Sub-Classes

Python:

class ColorPoint(Point):
    def __init__(self, x, y, color):
        super().__init__(x, y)
        self.color = color
    def __str__(self):
        return "{super} in color {color}".format(
            super=super().__str__(),
            color=self.color
        )

JavaScript:

class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y);
        this.color = color;
    }
    toString() {
        return `${super.toString()} in ${this.color}`;
    }
}

Those examples address your pain point of inheritance. Modern JavaScript can express classes and inheritance nearly identically to Python.

For set operations, see the Set object (compatibility). MDN offers basic set operation implementations:

Set.prototype.isSuperset = function(subset) {
    for (var elem of subset) {
        if (!this.has(elem)) {
            return false;
        }
    }
    return true;
}

Set.prototype.union = function(setB) {
    var union = new Set(this);
    for (var elem of setB) {
        union.add(elem);
    }
    return union;
}

Set.prototype.intersection = function(setB) {
    var intersection = new Set();
    for (var elem of setB) {
        if (this.has(elem)) {
            intersection.add(elem);
        }
    }
    return intersection;
}

Set.prototype.difference = function(setB) {
    var difference = new Set(this);
    for (var elem of setB) {
        difference.delete(elem);
    }
    return difference;
}

Or, alternate non-destructive implementations:

Set.prototype.union = that => new Set([...this, ...that])
Set.prototype.intersection = that => new Set(this.values().filter(it => that.has(it)))
Set.prototype.difference = that => new Set(this.values().filter(it => !that.has(it)))

You can't overload operators, but that's because Object + Object is already well-defined (to coerce both operators to a primitive value and then + those values).

Your final pain point is difficulty debugging asynchronous JavaScript code. Unfortunately, most of that is just that asynchronous code is difficult to debug. However, if you use Promises and async/await, you can write asynchronous code just like PEP 492 Coroutines with async and await. Asynchronicity is just hard to reason about in general, and it isn't JavaScript's fault here.


The trick to being able to use all of the niceties of modern ECMAScript is to use Babel to transpile your fancy, modern syntaxes down into browser-compatible JavaScript. If you want a language running on the web powering website interactivity, the only option is JavaScript, at least until WASM matures to the point it has GC and object interop with JavaScript, enabling bringing DOM methods into WASM.

  • 1
    My next question is "Babel vs TypeScript". But I will ask this question later, not today. – guettli Dec 6 '17 at 13:35
  • Please link here when you do. Thanks – Mawg Jan 11 '18 at 7:05
1

To address issue of nested function definitions and their callbacks you must start using the notion of a javascript promise which is quite nice - it eliminates callback hell

javascript ES6 handles set operations see http://2ality.com/2015/01/es6-set-operations.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.