Why did we do JSweet?


Posted on December 15, 2015 by Renaud Pawlak

In the past few years, many source-to-source compilers (a.k.a transpilers) have been created to improve JavaScript. Among them, the most well-known are CoffeeScript, Dart, and TypeScript, but the list of such languages is much longer. Transpilers have become such an attractive alternative for programming Web applications, that some proposals such as GPM have raised to standardize the transpilation process in ECMAScript 6. Most transpilers over JavaScript propose a new syntax (CoffeeScript, Dart), or a syntax extension to JavaScript (TypeScript). Some approaches propose to start from an existing language (examples: for Haskell and for OCaml.

JSweet falls in the latter category, starting from the Java language. JSweet is an Open Source Java to JavaScript transpiler that aims at programming modern Web applications (i.e. HTML + JavaScript) in plain Java, using our favorite Java IDEs. There are commonly two typically-given reasons why people would benefit such a transpiler.

  • Firstly, with HTML5 and its new JavaScript API, modern Web browsers have become the most universal execution platform, efficient and pluggable on most operating systems. For instance, the support of SVG and the canvas API allows the programmers to develop cutting edge UI, CSS transforms allows for animations that harmlessly take advantage of the GPU, CSS media queries supports adaptive design, debugging and profiling is natively supported by modern browsers, and so on. This makes it the most standard way to build cross-platform mobile applications, including mobile games.
  • Secondly, Java remains the most efficient language for building complex applications, with its world-wide community support for various IDEs. Its simple syntax and strong typing (but not too strong), makes it a good compromise for most developer profiles. For instance, Eclipse’s Java incremental compiler and refactoring tools make Java the most comfortable language to handle the complexity of large scale projects.

However, beyond these obvious reasons, many technical and “business”-oriented choices need to be made in order to build such a transpiler. In particular, the crucial issue to be tackled is the way to access the existing libraries, since it is a fact that, without libraries, a programming language is pointless. So the question that rapidly arises is: which libraries, and how do I get access to them?

The in-depth API transformation approach

In the past, many Java to JavaScript transpilers such as GWT  or Java2Script  made the choice to transform calls to a Java API (such as SWT for instance) into calls to native JavaScript libraries. This approach has the advantage of seamlessly leveraging the use of JavaScript APIs, so that Java programmers do not need to learn JavaScript at all. When GWT came out, it generated a lot of buzz and hope from the Java community, because most Java programmers do not want to learn JavaScript, but also because such a tool could save a lot of time (and money) when porting legacy Java code to build modern Web applications. As a consequence, people got all exited, because they hoped they could potentially save a lot of money by:

  • not having to learn JavaScript at all and therefore being able to re-use Java skills and experienced teams to build Web applications,
  • rapidly porting legacy Java software to Web software,
  • building more complex applications than JavaScript ones because they would benefit static typing and professional-quality tools and IDEs.

However, real life does not work this way… In practice, there are several flaws to this kind of approaches. Building a transpiler that supports up-to-date Java and JavaScript APIs is extremely difficult and involves a significant delay when compared to projects that directly use the latest APIs natively. The root cause for this is that, in most cases, Java and JavaScript APIs are designed quite differently since the targeted runtime environments (a JRE and a Web Container) differ in many ways. As a consequence, the required in-depth transformations make the system complex to understand and, consequently to debug. In practice, when building more complex applications, it is naive to think that one will not need to understand the details of the generated code, when fine-tuning the Web applications, and trying to use latest state-of-the-art frameworks. Also, it is naive to think that the most complex Java frameworks can be executed in JavaScript. To put it with different words, here are the two main reasons why this approach is not as promising as expected/advertised.

  1. The impedance mismatch is high between the Java APIs and the JavaScript ones, which requires complex and in-depth transformations – as an example, try to imagine how complex it would be to build a transpiler for porting automatically all C++ applications to Java! As a direct consequence, most complex libraries cannot and will not be entirely supported, leading to half-working systems, which are not acceptable for real-world projects.
  2. The Web languages, tools, and APIs evolve so fast, that it is mostly impossible to keep up with the pace and the variety of JavaScript frameworks out there.

So, why JSweet at all then?

The syntax mapper (WYSIWYG) approach

Being agreed that trying to transform Java APIs calls to JavaScript APIs is a too complex task, there is a more realistic approach that consists of completely dropping the Java APIs, and actually using the JavaScript APIs in the Java language. With such an approach, the Java to JavaScript transpiler becomes a syntax mapper between the Java syntax and the JavaScript syntax, all the rest remaining unchanged. Sometimes, I like to call this approach a WYSIWYG transpiler, because what you write will remain unchanged since you directly access the target language APIs, instead of using a source-level API and translating to target ones.

Of course, with such an approach, programmers will not be able to automatically convert most legacy Java code to JavaScript code. For instance, a Swing-based application will never convert to JavaScript, since there is no corresponding Swing API in JavaScript. This limitation is however a good and healthy limitation, because all other in-depth approaches will also hit this limitation sooner or later. Additionally, knowing that Java APIs will not be automatically transpiled, it does not mean that such a transpiler cannot help in manually porting legacy code, or sharing some part of the application between a Java and a JavaScript application. For instance, if the data model (transfer objects or persistent data layer) is written with the Java syntax, and if it does not use too much of the Java APIs, it is possible to share the same code in the Java-written server part, and in the JavaScript-written client part of the same application.

As a consequence, we believe that the syntax mapper (or WYSIWYG) approach is the best solution to bridge Java and JavaScript. Still, it remains the issue of accessing the JavaScript APIs from Java. How do we deal with fast pace releases and the variety of frameworks available in the JavaScript community? For this issue, JSweet proposes the first working solution to translate TSD well-typed libraries from TypeScript, to Java. This API translator currently makes JSweet the only technology to allow the Java programmers to actually take advantage of all JavaScript (not only subsets of it). I will describe this solution in a coming post.


JSweet Outils et méthodes

0