Julien Richard-Foy’s blog

js-scala and scala.js

People often ask me “what is the difference between js-scala and scala.js?”. Here is an answer (maybe biased because I’m one the authors of js-scala, so please tell me if I say something wrong).

js-scala is a Scala library for generating JavaScript code, while scala.js is a JavaScript backend to the Scala compiler. What does that mean?

scala.js compiles your Scala code into JavaScript code. It is just the usual Scala compiler that takes your Scala source files and produces JavaScript code instead of JVM bytecode.

  +------+                   +------+
  |      |                   |      |
  |.scala|  === scalac ===>  | .js  |
  |      |                   |      |
  +------+                   +------+

On the other hand, js-scala is a Scala library providing composable JavaScript code generators. You can use them in your usual Scala programs to write JavaScript program generators. Your Scala program is compiled to JVM bytecode using the usual Scala compiler and the execution of this program generates a JavaScript program.

  +------+                                             +------+
  |      |                   +-------+                 |      |
  |.scala|  === scalac ===>  |.class |  === java ===>  | .js  |
  |      |                   +-------+                 |      |
  +------+                                             +------+

What are the differences, pros and cons of these two approaches?

Language vs Library

The main difference is that js-scala is a library while scala.js is a compiler. Suppose that you want to write a JavaScript program solving a given problem. In js-scala you write a Scala program generating a JavaScript program solving the given problem. In scala.js you write a Scala program solving the given problem.

Let’s give an example: write a program computing the squares of a list of numbers.

Here is how you would write it using scala.js:

def squares(xs: List[Int]) = xs map (x => x * x)

You write it just as you would write it in Scala.

Here is how you would write it using js-scala:

def squares(xs: Rep[List[Int]]) = xs map (x => x * x)

Well, “not so different, that’s just a matter of type annotation”, you might think. Actually, the Scala code does not look very different from the first program because js-scala uses (a lot of) implicit conversions. After (some) implicit expansion here is how the js-scala program looks like:

def squares(xs: Rep[List[Int]]) = list_map(xs)(x => numeric_times(x, x))

I won’t go into the details of how js-scala gives you an API to combine code generators that looks like if you were writing a Scala program, I just want to insist on the fact that when you write a js-scala program, you write a program generator, not a simple program. Here, list_map and numeric_times are code generators that are combined together to make a generator of code that computes the squares of a list of numbers.

Even if we try to make js-scala code look like Scala code, you should not ignore that you are writing a program generator and not a simple program. This subtle difference has some strong implications.

First, a js-scala program actually contains two distinct programs: the program generator and the program to generate. When you reason about this Scala code you may have to distinguish between the two execution flows. Actually, sometimes you want to leverage the fact that you are writing a program generator (see the next section), but sometimes you just don’t want to and you’d like to just think about the program you want to generate. (I have to mention that there is another research project, Yin Yang, letting you think only of the generated program, hiding the fact that you are writing a program generator)

Second, you can not use (all) the constructs of the Scala language to write your generated program: you can only define the program you want to generate in terms of combinations of code generators (which are just libraries). For instance, it means that you can not use the lazy Scala keyword to define a lazy value in your generated program. A lazy value in your program generator will just be … a lazy value in your program generator. However, note that if the lazy keyword can not be used, we could reify the concept of lazy values as a library and make it possible to use this concept in the generated programs (but using another syntax than the usual lazy keyword). Nevertheless, thanks to Scala virtualized, you can actually use most of the Scala language keywords (if, while, val, var, match/case, and even new) to define your generated programs.

In summary, both js-scala and scala.js allow you to write a JavaScript program using Scala, but scala.js lets you do this by reusing the whole language semantics (“modulo a few differences”). In js-scala, you write a Scala program that combines code generators to produce the desired JavaScript program.

Leveraging Program Generators

Actually, when I say that a js-scala program is defined by the combination of JavaScript code generators, this is not totally true. Indeed, what you combine are not code generators but statements. Why is this distinction useful? Because you can apply several code generators to a same statement. For example, if you have a JavaScript code generator and a Scala generator for a given statement, then the code you write that uses this statement can target both the client-side and the server-side of your application. It can be useful for some shared concerns of Web applications such as building HTML fragments or validating forms.

For instance, using the HTML fragment definition library, you can define an HTML template representing a product in a shop as follows:

def showProduct(p: Rep[Product]) =
    el('span)("Name: " + p.name + ", "),
    el('strong, 'class -> "price")(p.price + " €")

This function returns a set of statements representing the construction the HTML fragment showing a product. The JavaScript code generator for these statements produces the following function:

var showProduct = function (p) {
  var div = document.createElement('div');
  var span = document.createElement('span');
  span.appendChild(document.createTextNode("Name: " + p.name + ", "));
  var strong = document.createElement('strong');
  strong.setAttribute('class', 'price');
  strong.appendChild(document.createTextNode(p.price + " €"));
  return div

And the Scala code generator produces the following output for the same set of statements:

def showProduct(p: Product) =
    <span>Name: { p.name }, </span>
    <strong class="price">{ p.price } €</strong>

The JavaScript and the Scala code generators produce very different outputs, each leveraging the target platform native APIs (the DOM API for JavaScript and the standard XML support for Scala).

The use of an abstract representation of statements makes it possible to produce two variants of the generated program, specialized for the client-side and the server-side.

Note that the abstract representation of the program to generate can be traversed and processed to apply some optimizations (like partial evaluation) so even if you target only JavaScript you can benefit from the program specialization process. (For the interested reader, these cool properties rely on staging, and, to my experience, the kind of situations where you enjoy the most the use of this approach is when you can write a compiler by just writing a staged interpreter.)

Due to the design of scala.js, you can not achieve the same degree of specialization as in js-scala: at some point you have to add some runtime overhead. For instance, you can reuse Scala functions (i.e. scala.Function2) in your scala.js programs but they won’t be compiled into JavaScript native functions: a complex JavaScript object with an apply property will be generated instead. The same applies to all the Scala standard library.

If you are interested in fun ways to generate JavaScript code from Scala code, you probably also want to have a look at jscala, a Scala macro that generates JavaScript code. The approach is different from both js-scala and scala.js: your Scala program is a JavaScript program generator, as with js-scala, but the JavaScript code generation is performed by the Scala compiler, during the expansion of macros.

blog comments powered by Disqus