Is J2ObjC good for your next mobile project?

For Fovea’s latest game Quadrus, we tried out an experimental technology developed by a team at Google called J2ObjC, a Java to Objective-C translator.

What is J2ObjC?

J2ObjC is a tool that translates Java code to Objective-C for the iOS (iPhone/iPad) platform. This tool enables Java code to be part of an iOS application’s build, as no editing of the generated files is necessary. The goal is to write an app’s non-UI code (such as data access, or application logic) in Java, which is then shared by web apps (using GWT), Android apps and iOS apps.

Our use case

For Quadrus, we developed the whole game engine in Java: the game objects (boards, pieces, players), game rules, artificial intelligence and game sessions. Our objective was to make an eventual Android version easier to happen, as well as to see if we can leverage our team’s experience in Java.

We used the Test Driven Development methodology: game engine was specified using JUnit tests that were handed to a Java developer. As components became ready, they were included by the iOS developer who then had to build the user interface around them.

Ease of use

As a total beginner with this tool, it took me about a day to setup everything properly. Things you’ll have to go through include compiling the tools, adding XCode custom rules for the java files and (eventually) have the JUnit tests running. As I recall, the JUnit part was a bit tricky but I got the tests to run from the console.

What worked?

In terms of features, everything worked as expected. As we wanted to be cautious about not getting into undiscovered bugs, we avoided any obscure java features. We only used basic SDK classes like Vectors, HashMaps and Arrays. Advanced things like threads and more are also being developed, but we didn’t had (and wanted) to test them.

What didn’t work?

Mainly, performance. As long as no artificial intelligence was involved, we could have shipped the product and never complained. But the level of performance of the translated code wasn’t appropriate for a computationally intensive task like AI. I’ll talk a bit later about that.

Other small problems we encountered:

  • The latest release does not provide support for arm64, you need to compile the source from git to get the feature.
  • We had to write a custom script to generate files called .mm instead of .m.
  • Methods names of the generated Objective-C are not usable directly.

Method names

A method defined like this in java:

public int setValue(int x, int y, int value) {...}

Is translated like this by J2ObjC:

- (void)setValueWithInt:(int)x
                withInt:(int)y
                withInt:(int)value;

To get things clean, we subclassed the generated Objective-C code:

- (void)setAtX:(int)x
          andY:(int)y
         value:(int)value
{
    [self setValueWithInt:x withInt:y withInt:value];
} 

Allowing us to write readable code on the iOS client side. An option to specify the generated Objective-C signature from Java would be a nice addition.

The Performance issue

Analysis

In our case, the hard work was to perform a lot of different small operations millions of times in under a second. The main reason I saw for the generated code’s slowness is Objective-C’s relatively slow message dispatch mechanism. Each time a method is called on an Objective-C object, the runtime has to look for the method into a hash map to execute it. It’s eventually cached, but still prevents code from being inlined and other compiler optimisations (thus making getters and setters more expensive for instance). To put this into numbers, it was about 50 times slower before optimising, and that’s just low-level “stupid” optimisations like making class members public and accessing them directly and all that sort of things.

Suggestions

I would have loved an option to tell J2ObjC that a method does not need to be dynamic, so it can be translated into a C helper function. Java’s final keyword could play that role I guess.

Instead of generating this:

@interface MyStuff
-(void)addWithInt:(int)i;
@end

it could then generate that:

void MyStuff_addWithInt(MyStuff *ms, int i);

Even better, for short methods (in Objective-C++):

inline void MyStuff_addWithInt(MyStuff *ms, int i) {
    ms->value_ += i;
}

Implementing those tricks manually led to a major difference in terms of performance.

The Trick: inline native code

You can inline native code into your java file, this is how I implemented many low level optimisations.

	/*-[ #if JAVA ]-*/
	public boolean foo(int k) {
		for (int i = 0; i < k; ++i)
			if (board.at(i) == k)
				return true;
		return false;
	}
	/*-[ #else
	- (BOOL)fooWithInt:(int)i {
		for (int i = 0; i < k; ++i)
			if (QBoard_at(board_, i) == k)
				return YES;
	    return NO;
	}
	#endif ]-*/

Also to notice, as I went into low level optimisations, some features lacked documentation. For example, a member called “abc” in a java class is translated to a field called “abc_” in the Objective-C class. I couldn’t find if directly using “self->abc_” was safe.

Conclusion

J2ObjC is a fine tool which accomplishes what it’s supposed to. If you do not perform computationally intensive tasks, it’s a great way to share code between iOS and Android native apps that I would recommend.

We saw that its main weakness is the missing options to customise the generated code, in terms of method names and for optimisation purposes.

The project is still young and it’s open-source, so let’s hope this will happen soon.

I’m a consultant and developer for Mobile, Web, Games and Apps projects. I co-founded Fovea 8 years ago.

Tagged with: , , , , ,
Posted in Blog
2 comments on “Is J2ObjC good for your next mobile project?
  1. Evan says:

    Hello
    I have a little problem figuring how the j2objc works. After downloading the latest j2objc and Xcode, i don’t know what next to do, i have a whole bunch of files downloaded.. Please can you make a little tutorial explaining how it works (with example pictures if possible). So that a beginner like me can follow your guide lines…
    Thanks so much..
    Evan