RubyFlux: a Ruby to Java compiler
github.com
github.com
Compile your ruby code to java with this new compiler.
Then compile your java code to javascript with GWT https://developers.google.com/web-toolkit/
Then run your javascript inside ruby with ExecJS https://gist.github.com/4106776
Bonus points if you can make your original ruby code interact with the javascript in the ruby VM.
I feel like I always see projects like this that have just started out, and provide no discussion of the difficult edge cases and how they will be supported. Correctly implementing a programming language is a really hard problem. Programming languages have tons and tons of subtle edge cases, like what happens if you add two objects of different types (think about the "wat?" talk: http://www.youtube.com/watch?v=kXEgk1Hdze0). If you don't get all these semantics correct, then your implementation won't be compatible with code written on other implementations.
Charles Nutter has obviously done a lot of work implementing Ruby in the past so is surely aware of all of this. I just wonder, when I see a project like this, what the ultimate plan is. Is it:
- the project is new and incomplete, but we plan to work on it until it correctly supports all semantics of the source language, even if the generated code gets uglier and more complicated as a result
- the project is new and incomplete, and we'll add support for more stuff but not get too worried about every last quirk of the source language, especially if it makes the generated code get too complicated
- the project is just an interesting hack, a fun side project, an experimental prototype or proof-of-concept, etc, and you shouldn't expect much compatibility.
Honestly I feel like the biggest feature of both Mirah and RubyFlux are their ability to produce binaries that have no external dependencies. You only pay for what you use, and in both cases you,really just doing normal JVM calls under the covers. What Mirah achieves through static typing, RubyFlux achieves by generating all method names as stubs on a base class.
As others have pointed out...it is also just a fun experiment :-) But that is how both JRuby and Mirah started out too.
I don't understand why someone wouldn't just write Java if they wanted to write Java.
I also don't understand why anyone would want generated code. The unnecessary abstraction leaves you less expressive and with less control.
Not trying to be a troll here, just hoping to learn something I'm missing.
I bet it's mostly for fun. He essentially extracted his JRuby JIT into a conventional compiler.
In other words, a neat hack.
If rubyflux winds up bypassing most of this overhead, it could be a major win. (Right now, I've got a project to try to use Scala to try to build a full-featured, reduced-boilerplate Android environment here: http://rst.github.com/positronic_docs.html --- but I'd really rather be using Ruby if the performance penalties could be ironed out.)
But the potential reasons for wanting it is that now the runtime is the JVM, MRI (Matz's Ruby interpreter). JRuby accomplishes using the JVM as the runtime for Ruby by reimplementing the Ruby runtime in Java. This is a different approach, one in which Ruby code is compiled to Java code, rather than using Java runtime interpret Ruby code.
Looking forward to more.
But since it's currently the #1 post on Hacker News, maybe people do have some use for a Ruby-to-Java compiler, so could you enlighten me?
Or think of it as the solution to a problem yet to be discovered - isn't that how most discoveries are made?
Either way great achievement.
Much easier would be: "Make this Java with one command to a cross-compiler".
Whether or not this has practical applications is irrelevant for now, the project seems to be in its infancy. Nonetheless, it's a good thing that the author is trying and tackling new concepts.
No, there's a distinction between a code translation and a code compilation. At an abstract level, it's the difference between an actual Turing machine encoded with a specific set of instructions, and a Universal Turing machine along with an encoded representation of a program. Logically equivalent, yes, but that's not the same thing as saying that they're actually the same thing. (If they were, this would mean that any Turing-complete languages would be the same, so you might as well just write COBOL!)
Compilation is not just a matter of "produce another piece of source code that appears to have the same logic when executed". With compilation, the only information required at runtime is the input to the program itself (which is never known at compiletime, unless your program is one massive thunk - which would be kind of a useless program!). When translating code to another language like, eg., Javascript, this isn't the case, because the input to the program isn't fed directly to the output of the translation; rather, both are fed to the interpreter which executes one on the other.
This applies whether the target language for the translation is itself an interpreted language or a compiled language, but in practice, the translated form of a compiled language (ie, C) can itself be compiled immediately as part of the translation, so this isn't really a relevant distinction there.
(By this logic, it would seem that javac is a translator, not a compiler, which is almost half-true, but only because Java itself blurs the distinction[1]. javac compiles Java code to run "natively" on the Java virtual machine, and that machine is virtualized on actual hardware. So no input is required at runtime from the perspective of someone inside the virtual machine; however, since we're outside that hypothetical bubble, we can't actually execute that code natively and need to run a second translation at runtime - ie, the "just-in-time" portion of the process).
The reason this distinction is important has to do with the portability, reliability, and predictability of the generated code. Compiled code is inherently less portable (or at least, no more portable) than the pre-compilation source (whatever that language is). This is why languages like C are compiled for a particular system. On the other hand, the compiled form "solves" a lot of the decision problems that don't require executing (or even knowing) the input before-the-fact.
An interesting example of this problem is hiphop-php. As one of the other commenters pointed out, when translating code from one language to another, you have to encompass all of the quirks of the language (like 'wat') properly. The hiphop-php output is incredibly large because it has to statically determine the actions required when, ie, two variables are added, but one is a number and one is a string. This is just a feature of a dynamically typed language, yes, but it's not an issue if you simply wanted to translate Ruby to PHP, because you don't have to factor in any of that logic at compilation time - rather, it gets factored out and passed on to the interpreter. To create a truly self-executing, compiled form, that requires solving a lot of this logic insofar as your target system will allow, which is a much trickier process - you can't just rely on the runtime or the interpreter to pick up the slack for you.
[1] Incidentally, this was one of Java's selling points back in the day - hard to believe now!
If you're looking for a tl;dr, you've come to the wrong place - not everything is so simple, and while I'm happy to explain my comments to people who ask politely (like isbadawi), I'm not really in the habit of writing MLA-style research papers on demand (and certainly not when the same information is already so widely and easily accessible).
This would be a broken transpiler. Headius factoring in all of that logic, just like hiphop-php.
Or maybe I've just been thinking about types too much recently!
LoadError: no such file to load -- ruby_flux-1.0-SNAPSHOT