Kolumne: The Good Parts

JavaScript als Plattform
Kommentare

JavaScript besitzt in der Webentwicklung einen hohen Stellenwert. Doch nicht nur dort fühlt sich diese Sprache zu Hause. Mit Node.js ist sie ebenso auf Servern vertreten, und IDEs erlauben mit ihr die Erstellung eigener Module. Auch auf Fernsehern, Spielekonsolen und Embedded-Systemen ist sie anzutreffen. Kurzum: Die Verbreitung von JavaScript scheint kaum mehr aufzuhalten. Doch was bedeutet das konkret für die Entwicklung der Sprache? Ist JavaScript mittlerweile vielleicht mehr geworden, als eine reine Programmiersprache?

JavaScripts mannigfaltige Sprachfeatures lassen extrem elegante und mächtige Problemlösungen entstehen, führen jedoch gleichzeitig häufig zu unleserlichem und extrem schwer wartbarem Code. Viele sind der Meinung, dies sei ein sprachinhärentes Problem, das sich mit JavaScript nicht lösen lasse. Die Konsequenz: Eine alternative Sprache muss her! Doch wie soll das funktionieren? Browser, die zu den Haupteinsatzgebieten von JavaScript zählen, können mit keiner anderen Sprache umgehen. Natürlich könnten neue Sprachen erfunden werden. Doch aus Erfahrung vergehen etliche Jahre, bis sich diese soweit etabliert haben, dass sie produktiven Einsatz finden – falls dies überhaupt gelingt.

Die Entstehung von Transpilern

Eine einfache, wenn auch geniale Lösung des Ein-Sprachen-Problems ist die Verwendung sog. Transpiler, auch Transcompiler oder Source-to-Source-Compiler genannt. Transpiler sind Compiler, die eine Eingabesprache nicht in Bytecode für eine spezielle Plattform oder VM übersetzen, sondern in eine andere Hochsprache überführen. In Zeiten von interpretierten und mit Just-in-Time-Compilern optimierten Sprachen kann diese Technik eine Möglichkeit bedeuten, alternative Sprachen auch in scheinbar isolierten Systemen wie JavaScript zum Einsatz zu bringen.

CoffeeScript – Ein bekannter Transpiler

Ein Vertreter der Sprachen, für die ein Transpiler existiert, ist CoffeeScript [1]. Wenig überraschend ist die Zielsprache dieses Compilers JavaScript. Applikationen können demnach in CoffeeScript geschrieben und anschließend in JavaScript übersetzt werden. Hierbei muss die Ausgangssprache keine Ähnlichkeit mit JavaScript besitzen.

Eine Klassendefinition in CoffeeScript demonstriert recht eindrucksvoll, dass die Ausgangssprache nicht zwangsläufig Ähnlichkeit mit der Zielsprache besitzen muss (Listing 1).

class Shape
draw: ->
throw new Error("Abstract method.")

class Circle extends Shape
draw: ->
# Draw the Circle

CoffeeScript besitzt Klassen, JavaScript lediglich Prototypen. CoffeeScript verwendet Einrückungen zur Identifikation von Blöcken, JavaScript geschweifte Klammern. Funktionen werden ohne das Keyword function definiert. Es handelt sich also tatsächlich um eine neue Sprache, die sich gravierend von der Zielsprache unterscheidet. Trotzdem ist es möglich, das vorgestellte Programm mithilfe des CoffeeScript-Transpilers in JavaScript-Code zu übersetzen (Listing 1).

TypeScript – Microsofts Idee von JavaScript

CoffeeScript ist bei Weitem nicht die einzige neue Sprache dieser Gattung. Mit TypeScript [2] hat Microsoft vor einiger Zeit einen weiteren Vertreter der JavaScript-Alternativen ins Rennen geschickt. Im Vergleich zu Sprachen wie CoffeeScript ist TypeScript keine komplett neue Sprache, sondern lediglich ein Superset, also eine Erweiterung von JavaScript.

Jeglicher gültige JavaScript-Code ist demnach auch gültiger TypeScript-Code. Allerdings besitzt TypeScript diverse zusätzliche Features, die JavaScript aktuell nicht bietet. So z. B. ein Modulsystem, Klassen, Interfaces und – wie der Name der Sprache bereits vermuten lässt – ein statisches Typensystem. Listing 2 zeigt zwei primitive TypeScript-Klassen und ein Interface. Diese wiederum werden verwendet, um einen Kreis in einen Canvas zu zeichnen. Das Beispiel demonstriert anschaulich die Verwendung von statischen Typen.

Auch TypeScript ist ein Transpiler, der seine erweiterten Sprachfeatures zurück in JavaScript übersetzt, um diese in aktuellen Engines zur Ausführung zu bringen. Der Compiler übersetzt in diesem speziellen Fall nicht nur den Quelltext, sondern überprüft und erzwingt darüber hinaus auch die Verwendung korrekter Typen.

Weitere Transpiler

Neben den beiden kurz vorgestellten Sprachen CoffeeScript und TypeScript gibt es eine schier unendliche Menge weiterer Transpiler. Die folgende Liste enthält einige der bekannteren Vertreter: LispyScript, Moescript, Dart, JavaScript++, StratifiedJS, Objective-J. Eine weitaus vollständigere Liste von existierenden Transpilern für JavaScript findet sich z. B. im CoffeeScript-Wiki [3].

Emscripten und Co. – Der nächste logische Schritt

Die bisherige Betrachtung galt vornehmlich Sprachen, die allesamt eines gemeinsam hatten: Sie wurden speziell zu dem Zweck entworfen, in JavaScript übersetzt zu werden. Was ist jedoch mit bereits existierenden Sprachen wie C, C++, C# oder Python? Lassen sich diese vielleicht auch in JavaScript-kompatiblen Code übersetzen? Die Antwort lautet natürlich ja. Auch hierfür werden wiederum Transpiler eingesetzt.

Einer der bekanntesten Vertreter dieser Gattung ist Emscripten [4]. Emscripten ist in der Lage, LLVM Bitcode in ausführbare JavaScript-Programme zu übersetzen. LLVM-Bitcode ist ein standardisierter Bitcode, der in unterschiedlichsten Maschinencode übersetzt werden kann. Er wird unter anderem von Clang [5], einem C/C++ Compiler, erzeugt. Wenn also Clang und Emscripten kombiniert werden, ist es möglich, C- bzw. C++-Software in lauffähige JavaScript-Applikationen zu übersetzen.

Mit Emscripten sind bereits zum heutigen Tag beeindruckende Anwendungen entstanden, die vollständig im Browser ausgeführt werden können. Hier eine kleine Auswahl, die Lust auf mehr macht:

Besonders in Kombination mit modernen Technologien wie WebGL, besitzt diese Art der Webapplikationsentwicklung ein extrem großes Potenzial. Es bleibt spannend, was die Zukunft hier noch bringen wird.

Abb. 1: Cube2: Sauerbraten – Ein First Person Shooter im Browser kompiliert mit Emscripten

Abb.2: Eine Qt-Applikation ausgeführt im Browser

JavaScript: Mehr als eine Sprache

Betrachtet man die zuvor beschriebenen Einsatzgebiete der Sprache und ihre Verbindung zum eigentlichen Produkt, stellt sich die Frage, ob JavaScript die Grenzen einer normalen Programmiersprache nicht bereits überschritten hat. Die Sprache hat eine Veränderung durchgemacht. Doch was genau ist aus JavaScript geworden?

Zu Sprachen, die speziell für die Übersetzung in JavaScript geschaffen wurden (CoffeeScript, TypeScript) gesellen sich jene, die üblicherweise in systemnahen Maschinencode oder Bytecode für VMS übersetzt wurden (Emscripten, jsc). Wenn man sich diese Entwicklung anschaut, dann muss man zwangsläufig zu dem Schluss kommen, dass JavaScript vielmehr eine Plattform zur Codeausführung geworden ist, als eine simple Hochsprache.

asm.js

Zu diesem Schluss sind auch diverse kluge Köpfe bei Mozilla gekommen und haben deswegen asm.js [10] ins Leben gerufen, das eine Brücke zwischen der Sprache JavaScript und ihrer Verwendung als Zielplattform schlagen soll.

Hat man erst einmal statisch getypte Sprachen wie C und C++, die zu JavaScript compiliert werden, so ergeben sich für eine JavaScript Engine neue Optimierungsherausforderungen. Natürlich entstehen aber auch viele spannende, neue Möglichkeiten. In Sprachen wie C und C++ weiß der Compiler, welchen Typ unterschiedliche Variablen besitzen, ob diese also z. B. einen Integer, eine Fließkommazahl, einen String oder ein spezifisches Objekt beherbergen. Diese Informationen können zur Optimierung der Programmausführung verwendet werden. Besonders für JavaScript Engines ist diese Information relevant, denn sie können Typen zur Optimierung normalerweise nur erraten. Demnach muss immer eine Art Sicherheitsnetz für den Fall existieren, dass sich ein Typ doch einmal ändert oder die angewandte Heuristik zur Bestimmung von eben diesem nicht das korrekte Ergebnis geliefert hat. Dieses Sicherheitsnetz kostet Systemressourcen.

Ist die Ausgangssprache eine statisch typisierte Sprache wie C oder C++, dann könnte dieses Sicherheitsnetz entfernt werden, da die Typen ja feststehen. Dieser Schritt würde zusätzliche Performance liefern und den Speicherverbrauch verringern. Dies sind natürlich angestrebte und zwingend nötige Ziele, möchte man JavaScript auf den Weg zu einer allgemein verwendbaren Plattform bringen.

Leider existiert hier ein Problem: JavaScript selbst besitzt keine Möglichkeit, Typen dieser Art zu annotieren oder der Engine in irgendeiner Form begreiflich zu machen. An dieser Stelle haben die Entwickler bei Mozilla angesetzt und die Spezifikation asm.js entworfen. Diese definiert ein konkretes Subset der Sprache, das sich besonders gut optimieren lässt. Darüber hinaus erhält diese Teilmenge einige neue semantische Komponenten. Alle Ergänzungen sind so gewählt, dass eine Engine, die diese Spezifikation nicht kennt, keinen Unterschied bei der Codeausführung macht. Ein Beispiel verdeutlicht das Konzept relativ leicht:

In asm.js ist es z. B. möglich, eine Variable als Integer, also als ganzzahligen Wert, zu annotieren:

function f(i) { i = i|0; }

Die logische Verknüpfung mit dem Wert 0 macht für beliebige Integer keinen Unterschied und ändert somit den Wert der Variablen in Engines, die asm.js nicht unterstützen, in keiner Weise. Eine asm.js-kompatible Engine kann diese zusätzliche Typinformation jedoch nutzen, um die Ausführung zu optimieren.

Ein weiteres Beispiel ist die Annotation von Fließkommazahlen. Diesen wird ein Pluszeichen vorangestellt:

function f(d) { d = +d; }

Wie bereits zuvor findet auch hier keine Änderung des Werts statt, sollte eine Engine mit asm.js nicht vertraut sein.

Neben diesen recht simplen Typannotationen definiert asm.js außerdem diverse Einschränkungen und spezielle Bedeutungen, die zusätzliche Optimierungen erlauben. Emscripten besitzt in seiner aktuellen Version bereits die Möglichkeit, asm.js-kompatiblen JavaScript-Code zu erzeugen. Erste Tests bei Mozilla mit einer teilweise asm.js-kompatiblen Engine zeigen großes Potenzial zur merklichen Geschwindigkeitssteigerung für Programme, die mit Transpiler erzeugt wurden.

Mit asm.js verhält es sich ein wenig wie mit echtem Assembler. Nur in Ausnahmefällen schreibt man diesen von Hand. In den meisten Fällen übersetzt ein Compiler eine Hochsprache in den benötigten Maschinencode. Auch auf asm.js trifft dies zu.

Die Zukunft gehört der JavaScript-Plattform

JavaScript hat bereits etwas geschafft, das zuvor keiner anderen Sprache gelungen ist. Sie ist zu einer echten Universalsprache geworden, die auf nahezu jedem System und jeder Technik ausgeführt werden kann: Webbrowser, Server, Embedded-Systeme, Fernseher, Spielekonsolen, Handys uvm.

Doch hier ist noch lange kein Ende in Sicht. Die außerordentliche Verbreitung von JavaScript hat zu einer Mutation der Sprache geführt: eine Weiterentwicklung von einer Hochsprache, hin zu einer Zielplattform für unterschiedlichste Konzepte und Sprachen.

JavaScript befindet sich gerade erst am Anfang dieser Reise. Ich für meinen Teil bin gespannt, wie diese Reise weitergehen wird. JavaScript als Universalplattform? Etwas, das Java nie geschafft hat, könnte mit JavaScript Wirklichkeit werden. Wie auch immer die Zukunft aussieht, sie wird uns weitere spannende Zeiten bescheren.

Aufmacherbild: Individuality concept von Shutterstock / Urheberrecht: Aleksandar Mijatovic

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -