JSweet: A transpiler from Java to TypeScript/JavaScript
jsweet.org
jsweet.org
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)
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.
interface Foo {} class FooImpl implements Foo {}
Object o = new FooImpl(); if (o instanceof Foo) -> compile error
The inability to even handle Java interfaces should be a clue right off the bat that this won't compile any non-trivial Java code base.
Lambdas are meant to be used like in JavaScript. It totally works. JSweet supports function references (MyClass::myFunction) and defines the JS Function object for passing plain object functions. No need for getClass(), hashCode() or equals() in JavaScript.
Regarding interfaces, the situation is quite different. JSweet does not support interfaces in the way Java supports interfaces. JSweet interfaces are mapped to TypeScript interfaces which are pure compile-time entities used only for typing (which differ strongly from Java's). That's why the code you quote will not compile in JSweet, but it does not mean that JSweet is wrong: it means that your way of understanding an interface in JSweet is wrong (unlike Java, JSweet interfaces have no runtime representation). This part requires further documentation though... JSweet is a very young project.
Generally speaking, when you program with JSweet, you have to stop thinking too much in terms of Java semantics, and start thinking more in TypeScript or JavaScript, at least for some cases. The very most of it remains close to Java and very intuitive to programmers, since IMO, Java and TypeScript are quite in the same language family.
It doesn't go to LLVM, it goes straight to ObjC/C. You can then import this into any XCode project.
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.
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?
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.
We're not talking about 100% JLS semantics, but if you can't even compile code that utilizes java.lang.* and java.util.*, why not just use Kotlin, Dart, Typescript, and other languages provide high level typed JS like languages.
Using a language that doesn't compile properly leads to all kinds of nasty surprises and hard to diagnose bugs.
JSweet is not meant to obey JLS because JSweet is "just" Java syntax. It is not Java anymore. However, some specific transformations (very few) have been implemented so that Java programmers are not confused by JavaScript runtime behavior (as explained here for instance: http://www.jsweet.org/language-specifications/#Variable_scop...).
JSweet is not meant to be at all compatible with Java legacy APIs. With JSweet, you will not even be able to access the Java Object API nor the Java String API. Instead you directly access the Object and String JS APIs. So who cares about JLS semantics then? What JSweet is trying to compile is JavaScript applications, not Java, and the examples show that it works for not-that-trival code.
In short, JSweet is for writing real JavaScript applications in a Java compile-time environment (not runtime). Nothing more, nothing less. I understand that GWT new generation it aiming somewhat at integrating JS apis too... But AFAIK, JSweet is the first project to give access to hundreds of JavaScript libraries in Java thanks to the TypeScript to Java API translator.
Putting GWT or Closure in the same category as JSweet, TypeScript, or CoffeeScript obfuscates what these tools do.
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.
As to your question, it doesn't really make sense for something to "change" from a transpiler to a compiler, any more than it makes sense to change from a Ford to a car. All transpilers are compilers; "transpiler" is just a little more specific. You know, like "gigantic" is a little more specific than "big", or "square" is a little more specific than "rectangle".
FWIW, I disagree with cromwellian that it's anything to do with optimization. I wouldn't personally say CPython transpiles Python to bytecode, but I'd also say an optimized transform from Dart to JS is a transpile. In my eyes, a transpiler is just any compiler where the target language is only intended to be written by humans.
(This changes over time, though. I'd probably not call Nim to C a transpile, although I might have in the past. We're probably reaching the point where X to JS stops being a transpile, too.)
You think that I can take a program, run it on some input in the past, and it's a transpiler, assuming that it fits the other part of your definition. Then I wait, say 10 years, run that same program on the same input and now it's not a transpiler?
I'd argue that terms like "interpreter", "compiler", "decompiler", "transpiler", etc. are helpful for establishing a general taxonomy of program transformation tools, even if the boundaries aren't so clear.
BTW, GWT, support in browser java debug via sourcemaps for a long time.
BTW, you don't have to debug in Chrome. If you attach IntelliJ to the JSVM, you can debug right inside your IDE, stepping over breakpoints in Java, etc. SDBG for Eclipse does the same things. (https://www.youtube.com/watch?v=icJEa5lcJaQ)
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.
Generating Java interfaces from TypeScript is coming soon. We have done this in the past from WebIDL in the Elemental library provided by GWT.
A new tool which can do it from WebIDL, Closure JsDoc, or Typescript (all three) is being developed.
Let us know if you are interested in collaborating on this (never hurts asking).
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.
Could you give me an example of any technology which you don't hate?
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.
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...
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.
If you desire a more granular control over cluster management you could use 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.
There's a library that fixes the sync I/O issue in Java call Quasar which implements lightweight threads called Fibers. I remember seeing it a while ago and thought it was pretty interesting and it seems reasonably mature now. One of the nicest things about it is you can get async IO with a sync programming model. So no callbacks and chaining of promises.
I'll probably start with Java 8 but the other JVM language I quite like it Kotlin, which has a similar style to TypeScript in some ways, and is designed for Java interop. Kotlin + Quasar fibers seems like a pretty nice combo on the JVM.
http://blog.paralleluniverse.co/2015/06/04/quasar-kotlin/ http://blog.paralleluniverse.co/2015/08/28/quasar-0.7.3-coms...
Does Quasar address this?
Edit: just to clarify: it's not as bad as I make it sound. Java may still be the best tool for your project. It's definitely got a great VM and good libs. If it makes sense, use it.
Comsat is the companion project which provides the quasar fiber integration to common libraries/services (http, servlet, db etc) which gives you the nice synchronous programming model (via bytecode instrumentation) with the async/light thread scalability.
So your incoming servlet request would use the async servlet API integration to move the execution to a fiber. Then calls to an external http service, out-of-process cache, files, NoSQL db etc would all happen within the fibers. Its mainly the JDBC that requires a pool of normal threads.
I've only just decided this is what I want to use next, so I'll be able to tell from experience over the coming months!
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).
This statement is patently false. I/O requests are fired off asynchronously in the main context but fetch data via background threads. In addition, in a multi-core/processor system you can use the 'cluster' module to fire off multiple instances (ideally 1 per core) of the HTTPD.
As for libraries. Node doesn't provide much in terms of 'batteries included' but the NPM registry has eclipsed the library ecosystem of every other language. If anything, the issue is too much choice as there are usually 3-5 alternatives for everything you can imagine.
The minimalist nature of the Node core is a 'double edge sword'. The downside is, it requires a lot more cognitive load and research to choose the libraries to use in a dev stack. The upside is, since most of the functionality is developed independent of Node the core devs can focus the entirety of their effort improving the platform/language/packaging. The effort of building all additional functionality is the responsibility of the community.
I have used Java some and C# a lot so I can understand why devs love the ecosystem and tooling. The tooling for JS is getting better over time but there's something to be said for IDEs that come prepackaged with all the tools necesssary to be productive.
Personally, I shifted over time embracing the flexibility of dynamic languages and shifted to a mindset that favors composition over structure.
If I may add some hopefully-constructive criticism, it feels that GWT (like some other well-known Google frameworks) is trying to address too many issues at the same time... But that's my own opinion and it does not mean I don't appreciate it.
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.
That said, that would be a really cool tool to have...
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.
ES5 will be continue to be the target to until either/both platforms are feature-complete.