Skip to main content

cfront: a J2ObjC Inspiration

Developers new to J2ObjC may find its "Java compiles to Objective-C, which compiles to .o files" approach a little strange, but it's based on precedent: cfront. When C++ was first released, no compilers translated C++ sources directly into object files. Instead, the cfront script translated C++ into temporary C files, and then invoked cc to compile them. cfront took similar options as cc, so most C++ developers used it as if it was a true C++ compiler. The cfront script wrapped around a transpiler, though; it was a script very similar to combining the j2objc and j2objcc scripts in J2ObjC.

One of cfront's innovations was name mangling, where C++ type information was embedded into C names. J2ObjC also uses name mangling (described here) to support features like packages and Java's method overloading semantics that Objective-C doesn't directly support. For example, the JRE has both java.util.Date and java.sql.Date classes; since C names are all global in scope, J2ObjC mangles those type names to JavaUtilDate and JavaSqlDate respectively.
As many developers have complained, name mangling produces ugly, hard-to-read code. For example Guava's simply named MultiSet class name becomes ComGoogleCommonCollectMultiSet. Even worse is when method parameter names are also mangled, since each parameter name needs to contain type information to support method overloading.

These complainers have my full sympathy. Way back when I ported cfront; since cfront was written in C++, new systems built it by compiling a set of cfront-created C files to create a bootstrap translator, then using that to build the real translator. That was rarely a problem on Unix systems, but since CTOS was a non-Unix system I had to pour over every mangled source file fixing issues before it could eventually translate itself.

cfront's example is also why J2ObjC is not recommended for one-time translation. cfront had a flag to just generate C code, but its use was discouraged and eventually removed since it generated code that only a C compiler should have to read. J2ObjC recommends this same approach: maintain and share Java source across platforms, using j2objc/j2objcc or j2objc/Xcode to build Java as part of an iOS application. It's a waste of developer time to use J2ObjC once and then try to maintain its output as a project source file, both because it's hard to read and because we're improving what code gets generated with each release.

Who knows? Maybe if J2ObjC is successful enough, compiler developers will take note and fold its functionality into their tools, like C compiler engineers did with cfront. Our team can declare total victory if we're made redundant!

Comments

  1. It's interesting to compare J2ObjC to RoboVM, which takes the approach of translating Java bytecode directly to ARM assembly so it can run on the iPhone. I suppose one benefit of compiling to Objective C is interoperability. It's easy to write Objective C that calls Java and vice-versa. I haven't looked into it particularly deeply, but I suspect that it's much harder to do that with RoboVM.

    ReplyDelete

Post a Comment

Popular posts from this blog

Mapping tests from TestNG to JUnit

In the summer of 2020, J2ObjC's JRE emulation library (a fork of Android's libcore library ) was updated from Android Nougat to Android 10. The update consisted of adding new APIs, and updating the existing code. Apart from general functionality changes, one of the main goals of the update was to port new test cases to better verify that the JRE emulation library works correctly. While updating the java.time package, I came across a tck.java.time package containing approximately 15,000 new test cases written in TestNG. The problem? J2ObjC only supports JUnit. Instead of supporting both TestNG and JUnit, we decided to build testng2junit , a tool that converts TestNG tests to JUnit. How Can These Frame works be Mapped? To convert from TestNG to JUnit, we needed to determine where the two testing frameworks differed. Attempting to run the TestNG tests through the compiler gave us plenty of compile-time errors to sift through. These syntax errors, coupled with documentation from

Catching Java exceptions in Swift via j2objc

TL;DR : it’s possible to handle Java-originating exceptions in Swift for j2objc -based projects. Scroll to the end for example code. It’s getting more common to call j2objc -generated Objective-C code from Swift as iOS development shifts to this modern language. At a high level, we can imagine this means calling Java code from Swift. But Objective-C is an important link in this chain and it shapes the way Swift interacts with the code that started its life as Java. j2objc  does a great job of supporting Swift’s features when called with the --swift-friendly  flag. This feature is particularly useful when the Java code is annotated with @Nonnull , @Nullable , and @ParametersAreNonnullByDefault  to enforce Swift’s optionality at compile time and as you type in Xcode. But there’s one important Java feature that gets lost in translation on the way to Swift: exceptions. You might expect to catch Java exceptions from Swift like: do {     // original Java code throw