Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Why Frege compiles to Java
Frege compiles to Java source code, instead of directly emitting Java byte code. For that purpose we use a Java compiler (either the eclipse compiler in the Frege IDE, or the one that comes with the JDK). In any case, the java compilation is just a method call and runs in the current JVM, though we have also the possibility to run an extra process to invoke an arbitrary java compiler of your choice.
Note: in the following, we're referring to the software that does the java compilation for us as
javac for simplicity. Again, that does not mean we need to fire up a process that runs
javac.exe or some such.
We're often asked about the rationale behind this choice and here are some:
Frege follows the unix philosophy of composing tools that do their job well.
javaccompiles Java code well.
javacintroduces another level of robustness as it ensures the creation of valid byte code (assuming correctness of
javacgives us an additional type check for free, as we strive for generation of warning-free fully generically typed Java code.
Java code can call other Java code and can be called from Java. Having the Java equivalent of your Frege code makes inter-operation much easier.
We follow the very successful approach of GHC that first compiles Haskell to intermediate languages. Java is one of our intermediate languages.
The Frege compiler becomes conceptually simpler as it is a Haskell-source to Java-source transformation.
The native interface can contain fragments of the java language like in:
native availableProcessors "java.lang.Runtime.getRuntime().availableProcessors" :: () -> IO Int
One would have to embed nothing less than a compiler for a subset of Java to ensure that
java.lang.Runtime.getRuntime().availableProcessors()is a valid java expression that yields an
int. The alternative would be to have a less flexible and convenient native interface.
javaccompiler is highly optimized and continuously improved for various platforms and JVMs. This is all work that we don't have to do.
The Frege compiler depends only on the JDK and nothing else.
The approach is future proof. For example, it is likely that radical changes proposed for the Java language like value types and primitive types as type parameters will not be possible without corresponding JVM changes. In the latter case, all what we'd have to do in the Frege backend would be to comment the code that is there to make sure that no primitive type ever appears as a type argument, and we're done and ready for the new era. In the former case, we could as well get away with doing nothing and still profit from the enhancements.
There are also quite some myths about this issue:
Some seem to assume that "manually" generated bytecode is somehow superior to the one generated by
javacin terms of performance. The truth is that the JIT is the instance that makes a JVM program fast. Experience shows that byte code optimization doesn't contribute much, if any, to performance optimization. But even if this were so, the tools that do such optimizations can still be applied to byte code finally created from Frege source code.
There is the issue of byte code features that are not available in Java. This is all fine, it is only that none of those features would be of any use in the implementation of Frege.
Even the famous
invokedynamicinstruction (which is quite important for JVM implementations of dynamically typed OO languages like Ruby) is not needed for statically typed non-OO languages like Frege where the majority of method calls go to static methods and the rest are calls to interface methods. You can't beat
invokedynamic, it's as simple as that.
Finally, some argue that the Frege compiler could be faster when it would generate byte code right away. Despite there being no empirical evidence, it is indeed conceivable that this would be so. However, in practice, this would amount to a few fractions of a second per module at most. In exchange, the compiler would be more complicated and less easy to debug.