June 9, 2009

Java on the iPhone?

Is it possible? Can you run Java on the iPhone? Well, no, at least not at this time. Perhaps never, due to the rules Apple have in place disallowing interpreted languages from operating on the iPhone. This is a real shame because quite frankly, Objective-C is not an easy language to work with. And since it is the only language we have to work on for the iPhone, our hands are extremely tied. (One could argue that Objective-C++ allows C++, but in my opinion, this is a much uglier situation than just coding in Objective-C.) I am a former Java coder. Java may not be the most enabling language (think Python or Groovy), but the grammar is clean and simple and arguments about Java being too verbose are lost when comparing it to Objective-C. I like the power of the Cocoa-Touch run-time environment. However, the vehicle to get to that power (Objective-C) is a nightmare. Objective-C is clunky, verbose, inconsistent, and archaic. It is loosely based on SmallTalk, a relatively unused language in the industry. There's a reason for that. To me, doing anything in Objective-C is painful. Take the mundane task of creating a dictionary and adding a key/value pair to it. In Objective-C, it would look something like this:
NSMutableDictionary* dict;
dict = [[NSMutableDictionary alloc] initWithCapacity:3];
[dict addObject:@"Some data" forKey:@"key"];
I have many issues with this code:
  1. Why does Objective-C insist of dealing with pointers? Since you can't instantiate an object on the stack like you can in C++, having to specify the "*" character is superfluous. The fact that these are pointers should be hidden, as they are in Java. In the rare cases you need to actually refer to the class name and not the pointer, use some other syntax.
  2. The [object method] call syntax is really whacked. My opinion is that this is not an intuitive syntax, nor is it easy to read or write. It is nearly impossible to visually parse, especially with nested calls.
  3. Semicolons? Come on. There is no reason why a language parser cannot figure out the end of a statement. These are artifacts from the days of Pascal and C when they didn't know better. Tcl, Groovy, Python, Ruby, JavaScript, et al prove that semicolons are extraneous syntax fluff. It's a shame that most programmers accept them as the de facto for languages, when in fact they indicate a poorly designed grammar.
  4. Look how verbose and awkward it is to add a single element to the dictionary. I get carpal tunnel syndrome just reading Objective-C code. Objective-C forces you to use positional arguments and named arguments at the same time. If it wasn't for Xcode helping to write Objective-C, it would be a horrid language to type.
  5. I miss the commas between arguments. These are not needless syntactical fluff, as the "*" and ";" characters are. Commas help visually separate arguments. Without them, the args all blend together and make it hard to read.
  6. What's with the @ characters in front of strings? I understand they are trying to differentiate between C-style string constants and NSString constants, but why give the simpler syntax to C? I have never used a C-style string in an Objective-C program. I would have made "string" automatically be an NSString constant, and if you want a dinosaur C-style string, then use @"string".
Okay, that's six major complaints in just 3 lines of code. This doesn't even go into my other major beefs, such as separate files for class definitions and declarations, the @property/@synthesize malarkey, the use of "@end" as a block terminator, etc. Java can do the same task a little better and with a much cleaner syntax:
HashMap dict;
dict = new HashMap(3);
dict.put("key", "Some data");
It still has those dumb semicolons, but this is still a major improvement. I know all this bitching and moaning doesn't accomplish much. Objective-C is the tool we have to work with on iPhone development. There is nothing you can do about it. Adapt and move on. And adapt I did. I tolerated Objective-C's quirks for months. But I always thought about how much easier and productive it would all be in another language. I couldn't let it go. Then I came up with an idea: What if I just used the syntax of Java, and not the Java run-time environment? What if I wrote a translator, one that translated Java code into Objective-C? How hard would it be? I think this is quite possible, as long as you lay down a few ground rules. I have accumulated a fair number of these ground rules and revelations from tinkering with prototypes. The above Objective-C code could look like this in Java syntax:
NSMutableDictionary dict;
dict = NSMutableDictionary.alloc().initWithCapacity(3);
dict.addObject("Some data", forKey="key");
Notice a few things different? But some things are the same. The most important aspect of this is how we pass parameters. The first parameter is passed like normal, but all subsequent parameters are passed as if they are keyword parameters (ala Python). Although this is parseable Java syntax, it wouldn't compile. But it can be translated to Objective-C very easily. The whole idea is boiled down to this: In Xcode, write your iPhone software using Java syntax. Calls to the Objective-C runtime and Cocoa Touch are pretty much the same. There are no separate .h and .m files, just .java files. Then run the Java code through a translator that generates the Objective-C .h and .m files, which then get compiled. Xcode provides the ability to run preprocess steps in a build operation. So you could set up your builds to translate your Java source to Objective-C, then the normal build process would take it from there. Another benefit is that Xcode will think you're typing in Java code (because you are, sort of), so you will get all the nice keyword highlighting and other editor shortcuts. This idea is not limited to Java. Although Python does not have static typing, the ShedSkin project proves that you can translate Python to C++, so it is likely possible to also translate Python to Objective C. But this situation is not perfect. For starters, any compile errors in the Objective-C source will have to be corrected in the original Java source. Unless you want to abandon your original source, you should never edit the generated Objective-C source code. Runtime debugging will have to be in Objective-C. For some, these problems may be enough to warrant this as an exercise in futility. I will reserve judgment until trying it in production software rather than just in tinkering. This introduction is just to whet your appetite of the possibilities. This project I call "Typhoon". Typhoon will comprise the set of language translators and any additional run-time support necessary. In future articles, I will describe some of the ideas of Typhoon. I invite readers to leave comments on what you think about this idea. Is it worth pursuing? Or is it an idiotic waste of time? Please let me know.

June 4, 2009

Multiple Parameters to Threads

This hint is fairly trivial, but I was surprised I could not find any information on this little "problem". I wanted to pass more than one parameter to a thread entry method. The standard NSThread class only supports 0 or 1 parameter to be passed, as can be seen in this initializer:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

Another way of starting a thread is with the method:

+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

But as you can see, this has the same limitation. The object parameter can be nil or some other parameter, but at most 1 parameter can be passed. Even the more modern NSOperation class has this same limitation and its remedy is pretty much the same as described here. There are two ways I see to overcome this limitation. One is more complicated than the other, but I will present both.  

Subclassing NSThread

The more complicated way is to subclass the NSThread class and override the main method to be your thread entry point. Since you create your own class, your initializer can accept any number of parameters, which you assign to instance variables. Then the main method can easily access this data:


@interface MyThread : NSThread
{
  NSString* data1;
  NSInteger data2;
}

- (id) initWithData1:(NSString*) data1 andData2:(NSInteger) data2;
- (void) main;

@end

@implementation MyThread

- (id) initWithData1:(NSString*) data1 andData2:(NSInteger) data2
{
  if((self = [super init])) {
    // save off our parameters
    self.data1 = data1;
    [self.data1 retain];

    self.data2 = data2;
  }

  return self;
}

- (void) main
{
  // no need to call [super main], as per the Apple reference docs
  // do whatever your thread needs to do
}

- (void) dealloc
{
  [data1 release];
}

@end


In order to kick off this thread, you do something like this:


// initialize it, passing all your parameters
MyThread* thread = [[MyThread alloc] initWithData1:@"hello there" andData2:23];

// now start it
[thread start];

// done with it
[thread release];


As you can see, this can be a bit involved, forcing you to create a new class, but it gets the job done.  

Stuffing Parameters

The other way is simpler, but at the same time a little clunkier. This way uses the simple initializer or the detach method as mentioned above. The way to get multiple parameters passed is to cheat: we pass a single container that holds all our parameters. Since this parameter is defined as id, it can be anything (as long as it is an object and not a primitive type). The perfect container is an NSArray. However, this is where things get a little clunky. First you have to create the array and populate it with your data. Worse is the fact that you can only put class objects into the array; scalars like integers will have to be converted to an object before adding.


// fire up a thread
[NSThread detachNewThreadSelector:@selector(myMain:)
                      toTarget:self
                    withObject:[NSArray arrayWithObjects:@"hello there",
                                        [NSNumber numberWithInt:23], nil]];


And then your thread entry method must pull the parameters back out of the array:


- (void) myMain:(NSArray*) parameters
{
 NSString* data1 = [parameters objectAtIndex:0];
 NSInteger data2 = [(NSNumber*) [parameters objectAtIndex:1] intValue];

 // the rest ...
}


Neither of these two solutions are perfect. The best solution, of course, is to write your thread code such that it doesn't need more than one parameter, but sometimes this is unavoidable. If any readers out there have any other ideas to solve this, I would love to hear them!