
JSweet: A transpiler from Java to TypeScript/JavaScript - renaudpawlak
http://www.jsweet.org
======
cromwellian
The GWT team has been working on a next-gen compiler that transpiles directly
to readable, JsDoc typed ES6, designed for high levels of optimization by the
Closure Compiler. Because of the new JsInterop system was designed for GWT
2.8, that is shared by both GWT and this new compiler, low impedance interop
between Java and JS will be possible, as well as a tool that reads WebIDL and
typescript libraries, and generates Java types.

As an example if the level of low impedance between the languages, consider
the @JsFunction annotation,

@JsType(isNative = true)

interface EventTarget {

    
    
      void addEventListener(String event, EventListener listener);
    

}

@JsFunction

interface EventListener {

    
    
      void onEvent(Event event);
    

}

Using Java8, you can write code like:

document.createElement("button").addEventListener("click", x ->
Console.log("Hello World"));

The difference between GWT running this, and the new compiler, is that the
output of the new compiler is a standard ES6 module.

The JSweet claims about GWT are out of date. First of all, in-browser Java
debugging has been available for years. GWT was in fact, the very first
transpiler to leverage Chrome source maps. I demoed this three years ago
([https://www.youtube.com/watch?v=-xJl22Kvgjg](https://www.youtube.com/watch?v=-xJl22Kvgjg))

Secondly, GWT has a "reversible and compatible" JsInterop system that provides
full two way low-impedance bidirectional interop, you can even do things like
subclass JS objects from Java, or define "fields" via @JsProperty which invoke
methods ala Object.defineProperty()

Third, the JSweet stuff looks like it doesn't obey standard JLS semantics.
Does it even compile the JRE or Guava? This is absolutely vital for code
sharing between platforms (e.g. server, Android, j2objc). If you can't run
standard JLS semantics, there's little point to writing the code in Java in
the first place.

~~~
stickfigure
_If you can 't run standard JLS semantics, there's little point to writing the
code in Java in the first place._

I'm an old user of GWT and hopeful for its revival, but I strongly disagree
with this statement. There are two ways of going about this - one is to hew
closer to Java semantics (the GWT approach), the other is to hew closer to
Javascript semantics. Strict JLS semantics is great for bulk compiling huge
projects, but sucks for interop. In the new GWT, does Long become a javascript
number? In the old GWT it was an opaque object, which was a constant irritant
when interacting with JS.

There is room for both approaches, but as a web developer, I need to interop
with JS frameworks more than I need to compile Quake.

~~~
skybrian
Emulation is a matter of degree. There are certainly many places where GWT
takes a shortcut or doesn't support a feature compared to a real Java VM. But
the idea is to get it right for most of the code a Java developer is likely to
write, so you have a chance of writing portable code and getting it to work
everywhere without a wholesale rewrite.

In particular, mapping Java longs to doubles doesn't make sense. If it's your
own code, why are you using long instead of int (or double) which perform much
better and interoperate well with JavaScript? If it's someone else's code, how
do you know it doesn't need the full 64-bit range?

~~~
stickfigure
It makes a ton of sense when working with identifiers, which is so common that
it's almost the standard usage of java.util.Long. In most practical
applications you can safely assume that identifiers are not going to use the
full 64 bit range. And being able to pass them to javascript frameworks is
incredibly useful - which is to say, the inability to use them in JS was
incredibly frustrating with GWT.

~~~
cromwellian
GWT 2.8 already does this. Long are passed as doubles unless they exceed 2^32.
Also, Double and Boolean are now unboxed native values. And Object[] can be
transparently passed to JS and back. Moreover, varargs work between JS and
Java, maintaining the semantics of both sides to work correctly.

If you want to build true hybrid apps that combine Java and JS programs,
there's a lot more considerations that have to be made, we learned some hard
lessons the last 3 years on Inbox, which is why JsInterop was redesigned 3
times to get the semantics sound.

------
monocasa
<soapbox>I really dislike the term 'transpile'. It's just a compiler. There's
nothing really different in theory or implementation of a "source"->"source"
vs a "source"->"binary" compiler. If I were to write a CPU in HDL that
natively executed JavaScript, would this change from a 'transpiler' to a
'compiler'. The distinction made is simply what the end user is going to do
with the result.</soapbox>

~~~
cromwellian
I like the distinction in the sense that transpilers generally don't do
optimization. GWT, Dart2JS, and Closure Compiler aren't transpilers in this
sense. They are full blown optimizing compilers.

Putting GWT or Closure in the same category as JSweet, TypeScript, or
CoffeeScript obfuscates what these tools do.

~~~
monocasa
So if I run gcc with -O0, it's a transpiler? Remember that gcc outputs a human
readable language that another program (the assembler) converts into machine
code.

~~~
cromwellian
In one sense yes, but GCC the utility is an optimizing compiler.

Would you call a sed script which converted Java to ES6 via regexes a
compiler, even though not an ounce of compiler theory was used?

I would define transpilers as a subset of compilers that are are only
interested in high level language conversion.

It's the difference between say, translating books between foreign languages,
and being an editor who rewrites a book to be better.

~~~
monocasa
I mean... sed is Turing complete. Yeah, it's in the Turing tarpit, but if you
were able to successfully translate Java to ES6 in a sed script, yes I would
call that a compiler. In a lot of ways, much of compiler theory is concerned
with the best way to write a compiler (for many different optimization
functions of "best"), not the only ways to do so. Just being a crappy compiler
doesn't make it any less of a compiler.

------
solomatov
I don't get why this library is better than GWT.

~~~
timv
The essential argument seems to be 2 things:

1\. It can generate node.js compatible JavaScript so you can run Java code in
node. I'm not sure how many people have felt the need to do that, but it's not
something GWT can do.

2\. It understands TypeScript, so it can make use of the work people have done
to (essentially) create type annotations over various JavaScript libraries,
and automatically (? or at least painlessly) build Java wrappers for them.

~~~
solomatov
Why anybody wants to run node.js instead of Java. Java is much better suitable
for the server side than node.

~~~
nothrabannosir
Nobody has commented yet. I can only guess this is because all agree: it goes
without saying that this sweeping generalisation is patently untrue.

Still, allow me to humor you and give just one (of the many) reason(s) why:
async I/O.

Yes, it's possible in Java. Yes, Java has futures that make it not just
possible, but also a reality in this universe.

Unfortunately, Java has made the inconvenient decision to retain backwards
compatibility and keep all its synchronous I/O operations available. Perhaps
not a complete folly. For all of the good that decision has brought, there is
one downside: any code (any lib) can still lock up an entire OS thread.
Result: all libs actually do this. No matter how Future-istic your codebase;
use _any_ lib and you're back to sync I/O.[1] This is absolutely killing for
high concurrency, I/O bound servers, who now lock up not just an FD or two per
conn, but also an entire OS thread.

Javascript's threading model, on the other hand, is so shit that it came out
the other side. By being inherently single threaded, all blocking I/O must be
done through callbacks. Result: _you can 't block an OS level thread in
javascript!_ So all libraries are inherently async (from the OS level).

There are, of course, many more reasons why Java is not "much better suitable
for the server side than node", but this is just one of them (libraries,
existing knowledge in your org, community, ...). In reality, both have their
uses. Node has proven itself by now.

Disclaimer: I actually hate Javascript. And Java. Including Java 8 (for all
the shit it, wisely, keeps around).

[1] E.g. Amazon's official AWS SDK, which is sync IO. Want async IO for S3 (or
anything there)? Write it yourself. Which you won't. Because there's already a
lib. "But it's not async!" // TODO.

~~~
carterehsmith
I hope we can agree that, whether Netty or Node can accept 100M connections
per millisecond or not -- is irrelevant if the rest of your stack cannot keep
up.

In most applications, eventually you need to hit the database to process the
request... and the database does not care if your original http request was
asynchronous or not... it will still take its sweet time in milliseconds (or
seconds for complex queries) to respond.

And the best way to prevent that is caching.

And that is where Node is at disadvantage.

In Java (and C, and C#, and a bunch of others), if your server has 16 cores,
you will be running a single process on 16 cores and probably 32 concurrent
threads, and they can all access some shared data (notably, database cache)
with low intra-process latency, using some simple sharing primitives.

Now, Node... if a Node process is single-threaded, then one would need to
spawn 16(32) Node processes to fully utilize the server, and they will be
using inter-process communication to talk to each other -- much slower than
Java's intra-process.

~~~
EvanPlaice
In Java (and C, and C#, and a bunch of others), if your server has 16 cores,
you will be running a single process on 16 cores and probably 32 concurrent
threads, and they can all access some shared data (notably, database cache)
with low intra-process latency, using some simple sharing primitives.

You're right but there are downsides to this approach.

First, you're creating a single point of failure. If any part of the
application crashes for whatever reason it brings everything down with it.

If you intend to have fault tolerance, maintain uptime during updates and/or
provide A/B testing capabilities, you'll still require at least a redundant
server and a load balancer to funnel incoming requests between the two.

Second, sharing memory across cores comes at a cost.

A simple mutex/lock strategy will work but will be inefficient as it blocks on
both reads and writes to shared data.

You could choose to use a CAS (Compare and Swap) strategy to avoid locks
altogether. As long as you can ensure your models as well as all of the
internal data structures they use are immutable and thread safe. Considering
the nested nature of OOP inheritance as well as language level access
restrictions on classes/methods/members, it can be difficult/impossible to
ensure immutability without hand-rolling your own data structures.

Third, sharing state across contexts comes with hidden costs that need to be
taken into consideration. For instance, if the shared state for all threads is
updated (ie a cached value is added/updated) it will invalidate the L1, L2,
and L3 caches on the processor. The overhead of cache invalidation increases
in proportion to the number of cores/processors involved.

Source: [http://www.drdobbs.com/architecture-and-design/sharing-is-
th...](http://www.drdobbs.com/architecture-and-design/sharing-is-the-root-of-
all-contention/214100002?pgno=1)

I assume you have experience with multi-threaded programming. I won't touch on
the transient nature and inherent difficulty in replicating bugs introduced in
multi-threaded programming. Other than to say, I've done enough of it in the
past to develop a very healthy fear.

\-----------------------

What about Node...

You're right to assume that Node instances will run as a cluster. Ideally one
instance per core, to reduce context switching and prevent cache invalidations
between the foreground and background workers internal to a Node instance.

As for a cache layer between the DB and Node instances. Since communication
between Node instances will happen at the OS level via IPC, there's no benefit
to implementing a global cache internal to the Node application. Instead, it
would be better to offload the responsibility to a separate service that is
specialized for caching (ex redis). This reduces the complexity of the
application, surface area for bugs, and development time.

Load balancing will be required anyway, so it makes sense to use Nginx. Nginx
is much more fault tolerant, providing sane limits for incoming requests, as
well as the ability to define routes that short-circuit requests to static
files.

What's interesting about deploying a Node cluster is its 'redundant by
default' nature including auto-respawning of cluster instances
[https://www.npmjs.com/package/express-
cluster](https://www.npmjs.com/package/express-cluster).

If you desire a more granular control over cluster management you could use
[https://github.com/Unitech/pm2](https://github.com/Unitech/pm2).

To make this work the servers themselves will need to be stateless. Which
means, handling session management requires additional work-arounds.

\-----------------------

Java is likely 'faster' when deployed in a strictly vertically scaled setup.
Node.js is more geared to horizontal scaling by default. Just like Java now
includes good support for async request handling, I have no doubt the
community will design tools that also favor scaling out.

Either way, I don't think raw performance is going to be the deciding factor.
Choice of platform is a business decision that depends on the resources and
skills and/or preference of the team responsible for development.

------
TheAceOfHearts
A few weeks back I was looking though some java code and I was hopeful I'd be
able to transpile it in order to run it in the browser. I'm very experienced
with JS and its ecosystem, and I figured that java was so popular that it
should be straightforward to achieve this. But unfortunately, after 2 days of
screwing around, I didn't have any luck.

I'm not sure if it's due to my unfamiliarity with the java ecosystem or if the
tooling or documentation were just poor.

In any case, this tool looks friendlier than GWT, so perhaps I'll give it
another try at some point.

------
crudbug
I would rather make TS to JVM & CLR Bytecode, to have a unified ecosystem from
the opposite side.

------
ggonweb
What are the good options to convert from Javascript to Java or to other high
level languages?

~~~
renaudpawlak
Transpiling from an untyped language to a typed one would give you horrid
results in most cases. The practical way would be to use TypeScript to compile
your program (JavaScript programs compile fine with TypeScript) and start to
manually transform your JavaScript code to add objects and types.

That said, that would be a really cool tool to have...

~~~
ggonweb
Has anybody tried Mozilla Rhino [https://developer.mozilla.org/en-
US/docs/Mozilla/Projects/Rh...](https://developer.mozilla.org/en-
US/docs/Mozilla/Projects/Rhino/JavaScript_Compiler)

------
warfangle
Why ES5 instead of ES6/2015?

~~~
renaudpawlak
I am not sure to what your question is referring to, but FYI, JSweet follows
the same pace as TypeScript in terms of JavaScript generation. So it already
supports most of ES6 AFAIK.

~~~
warfangle
None of the sample code exposes a) es6 module format b) amd module format c)
commonjs module format....

It's all closure-based jquery plugin module format.......

If you're gonna compile to "javascript" either target a version of node that's
been released in the past year or target webassembly.

Otherwise you're just another coffeescript.

------
hardlystriclyjs
possibly related: can some news hacker please create an internet crawling worm
that untranspiles all the javascripts that it crawls and turns them into wars
for everyone who wants to go the other way? I guess we also need mozilla
developer network to create a browser plugin to run the war files for a given
site, perhaps npm would host the wars, so we can use node to get the wars from
npm for the plugin. thanks

