-
Notifications
You must be signed in to change notification settings - Fork 145
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.
javac
compiles Java code well. -
Calling
javac
introduces another level of robustness as it ensures the creation of valid byte code (assuming correctness ofjavac
) -
javac
gives 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 anint
. The alternative would be to have a less flexible and convenient native interface. -
The
javac
compiler is highly optimized and continuously improved for various platforms and JVMs. This is all work that we don't have to do. -
Having the Java source code available opens all kinds of possibilities to use other compilers/transpilers like the ones for Java-to-JavaScript or Java-to-Dex (for Android).
-
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
javac
in 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
invokedynamic
instruction (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 beatinvokestatic
withinvokedynamic
, 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.
Home
News
Community
- Online Communities
- Frege Ecosystem
- Frege Day 2015
- Protocol
- Simon Peyton-Jones Transcript
- Talks
- Articles
- Books
- Courses
Documentation
- Getting Started
- Online REPL
- FAQ
- Language and API Reference
- Libraries
- Language Interoperability
- Calling Frege From Java (old)
- Calling Java From Frege
- Calling Frege From Java (new)
- Compiler Manpage
- Source Code Doc
- Contributing
- System Properties
- License
- IDE Support
- Eclipse
- Intellij
- VS Code and Language Server
- Haskell
- Differences
- GHC Options vs Frege
- Learn You A Haskell Adaptations
- Official Doc
Downloads