At Wealthfront some engineers believe that “A well-typed program never goes wrong” and that’s why we like statically typed languages (we mainly use Java for our back-end). We also appreciate the expressiveness of dynamically typed languages and the power of functional programming (we use JRuby and Javascript in the front-end).
Scala and Clojure seem to be good candidates for offering type-safe functional programming on the JVM, however they lack the excellent IDE integration which exists for Java. Therefore we’re using Google guava in our Java back-end which is a good but verbose solution (JDK 8 lambda expressions will probably help).
I recently had to write some javascript front-end related code, and was looking for a solution with the following capabilities:
- type-safe
- functional
- JQuery compatible
- excellent IDE integration (refactoring, auto-completion, …)
I could not find any existing solution (even though a long list of languages compile to Javascript). At the same time, one of my friend started working on this Java/JQuery/Eclipse/Maven project that leverages the type-safety and Eclipse integration of Java, with the convenience and functional style of JQuery. The project is named ST-JS (Statically typed Javascript) and is in the process of being open sourced. We’re only using ST-JS for prototyping at that point, no production code yet.
All you need to install ST-JS is to add maven dependencies to your project in Eclipse, and the compiler will start converting your code each time you save a file (it is relying on the incremental compilation feature of JDT and m2e).
Let’s start with a simple snippet:
public class Example1 { static String helloWorld() { return "Hello World!"; } }
Generated Javascript:
Example1 = function(){} Example1.helloWorld = function() { return "Hello World!"; }
Pretty straightforward, huh? No let’s take a look at a some code that deals with JQuery and DOM elements:
import static org.stjs.javascript.jquery.GlobalJQuery.$; import org.stjs.javascript.jquery.Event; import org.stjs.javascript.jquery.EvtHandler; public class Example2 { static void bindClickOnButton() { $("#ex-button").click(new EvtHandler() { public void onEvent(Event ev) { $("p.neat").addClass("ohmy").show("slow"); } }); } }
Generated Javascript:
Example2 = function(){} Example2.bindClickOnButton = function() { $("#ex-button").click(function(ev) { $("p.neat").addClass("ohmy").show("slow"); }); }
Note that ST-JS comes with a set of utility classes which allow you to write Java code that looks a lot like what you would have written in Javascript. It defines global variables available in browsers (window , document,…) as well as global functions (toFixed, ….). ST-JS comes with JQuery integration, but you can integrate any existing library.
If you have been reading this blog for a while, you can probably guess what’s next…. Testing! ST-JS comes with a NodeJS integration package (js-test-driver will come later). While you write JUnit-tests, the generated code is executed in NodeJS and failures are reported as JUnit failures:
import static junit.framework.Assert.assertEquals; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(NodeJSTestRunner.class) public class UnitTestExample { static class MyPojo { private String y; public MyPojo(String y) { this.y = y; } } @Test public void shouldCompainIfFooIsNotBar() throws Exception { MyPojo pojo = new MyPojo("Foo"); assertEquals("bar", pojo.y); } }
yields:
junit.framework.AssertionFailedError: Expected bar got Foo at org.stjs.testing.NodeJSTestRunner$1.evaluate(NodeJSTestRunner.java:60) …