My hobbyist coding updates and releases as the mysterious "Mr. Tines"

Sunday, 11 January 2009

Python swinging both ways

Following up to the last post I made in my quest for a cross-VM (JVM and CLR), single code-base, polyglot language stack, which doesn't involve any more Java than can be helped. Especially when there is Scala to play with, a language which a reading of the stairway book shows is very nifty indeed.

To summarise where we are, and what we have discovered to date --

  • Python can call Scala and Java happily
  • Java calling into Python is funky and platform dependent; doubly so for Scala
  • Scala cannot both call into java.* classes and compile on .net
  • Low-level Scala pre-defs differ in the Byte type (signed in Java/J#/Scala-JVM, unsigned in Scala-msil)
  • Ruby's predilection for Pascal-case namespaces (fudged in JRuby to match Java's lower-case convention) would require a lot of plumbing around in C# to mate IronRuby to J# or Scala-msil (as the rest of .net uses Pascal-casing).

And then there is this weekend's discovery.

As J# is a barely JDK1.2 implementation at best, I can't use the latest Java splash-screen feature, and have to fall back on older implementations. I have one to hand, back from c. JDK 1.4 days. It uses synchronized(), Object.wait() and Object.notifyAll().

The first is easy enough to deal with when wanting to put as much as possible of this GUI-driving code into Python -- define an interface to hold a code block

public interface ISynchronizedAction
{
  void performAction();
}

and then have a class which knows about the object to synchronize on, and can execute the block in a synchronized scope

public class Synchronized {
  private Object lock;

  public Synchronized(Object lock) {this.lock = lock;}

  public void Lock(ISynchronizedAction action)
  {
    synchronized(lock) {action.performAction();}
  }
}

Except in IronPython, I also discover by dumping the dir() of an object sub-classing java.awt.Window -- inheritance being needed for the splash-screen window class rather than composition, in order to hook the update/repaint APIs -- that neither Object.wait() nor Object.notifyAll() are present to be called. Fortunately the object I want these methods on is the same one I want to synchronize on, the splash-screen window itself, so I was able to just extend Synchronized with

  public void delegateWait() throws InterruptedException
  {
    lock.wait();
  }

  public void delegateNotifyAll()
  {
    lock.notifyAll();
  }

and make the there-and-back-again calls as required.

Then I just had to work around the older dialect's lack of support for .png (by using a .gif) by using the handy Java-1.1 compatible javapng-1.3.0 library to actually paint the image into the splash screen.

As usual, Jython needs the helper .jar file in the CLASSPATH, while IronPython can reference the equivalent .dll from code by assembly file name.

2 comments:

Konrad said...

I'm not sure if that's what you need, but Java can call Python code quite easily. It must be run through Jython though, and implement Java interface. All you need to do then is to create a factory that returns your objects. It is described here:

http://wiki.python.org/jython/JythonMonthly/Articles/October2006/3

Steve said...

And you can do the same trick of implementing an interface to publish IronPython objects into J#. It's just that the details of the implementation to achieve J# -> IronPython differs significantly from Java -> Jython; unlike calling in the other direction.

For my peculiar requirement of having a codebase that runs in both environments, the lack of conditional compilation in Java makes this cumbersome, to say the least. Going Python->Java/J#, the platform selection can be smoothed over by a conditional import.