Monday, June 13, 2011

Android roadbumps

As some of my readers know, I'm writing Android apps. It's been slow. The Java learning curve is actually fairly steep (at least as compared with high level languages I've been working in like Perl, Python and so forth). Just to give you a taste of what you have to look forward to if you want to do some Android development, here's what I've been fighting with today.

First, I had a really silly problem. I had a list and I'd defined a callback called onItemSelect for it. I set a breakpoint in this method and ran the app under the emulator. Click. Click. Click... nothing. I kept going over the code and trying to figure out how this could happen. Click. Nothing. Damn!

So then I was just messing around in the emulator and accidentally hit the scroll wheel. Bang! My callback is invoked! After scratching my head for a second, I had a brain storm. I checked to see if there was an onItemClick callback, and indeed there is! What onItemSelect does is apparently handle selecting, but not clicking on an item. What I'm not sure of is how you could manage to select an item without clicking on it outside of the emulator... honestly, I can't figure out of this is even useful. Maybe if you used the D-pad to navigate a list...

Then, I was trying to write a class that handles a download for me. It needed to take two parameters that represent callbacks. Now, Java is kind of neurotic about insisting that there's no such thing as a function, so when you want to do something that's clearly functional like passing around a callback, you have to do it in terms of an object oriented behavior like sub-classing. I can't begin to explain how horribly wasteful this is in terms of coding and efficiency, but let's just get past that. Here's what I tried to write:

Class file A.java:

import B;
class A {
  public void registerCallbacks() {
    B.new(new B.OkCallback() {
      @Override
      public void callback(String result) {
        // do stuff with result
      }
    },
    new B.FailCallback() {
      @Override
      public void callback(String message) {
        // deal with failure represented by message
      }
    }).execute();
  }

And in B:

  class B {
    public void execute() {
      // do stuff
    }
    public abstract class OkCallback {
      public abstract void callback(String);
    }
    public abstract class FailedCallback {
      public abstract void callback(String);
    }

Ignoring the obvious duplication (since it wasn't that simple in my real code), there's only one error, but it's a really hard thing to find if you're new to Java: "static" is required on the definition of both abstract classes. I'm not entirely sure why you would ever define a non-static, abstract, nested class, but I guess there's some application for declaring child classes... still, it seems like this kind of runaway syntax is just absurd. To give you an example, let's look at a hybrid functional/OO language like python:

  from B import B


  def handleResult(result):
    # do something with result
  def handleFailure(message):
    # do something with failure message
  class A(object):
    def registerCallbacks(self):
      B.registerCallbacks(handleResult, handleFailure).execute()

Python file B.py:

  class B(object):
    def execute():
      # do stuff...

Notice that, not only is the code simpler, but the extra layers of object-creation, subclassing and all of that noise are gone from the call stack. You pass a function to B and it invokes it when needed, with the appropriate parameters.

Even in Perl, functions can be passed as subroutine references and invoked by the caller. In C and C++, function pointers aren't the same thing at all, but for simple callbacks, they work well enough.

Java is fundamentally flawed in this way, and I'm hoping that they crank out a version 8 or whatever, wherein they finally give up and allow real functional programming.

No comments:

Post a Comment