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

Thursday, 31 January 2008

Confusion of Babel

I really would like to put a functional layer in the cross-VM stack, but...

Ocamljava and F# might be code compatible, but the former has a cumbersome build and interop process (and doesn't seem to advertise call-from-Java); while Bigloo seems entirely silent on interop.

Cross-compiling Scala class bytecodes to CLR doesn't seem to be a goer -- IKVM balks at referencing CLR 2.0 assemblies. I might be able decompile the classes and rebuild them via J# -- the hiccup there is that I would have to translate the runtime .jar as well -- my simple "Hello World!" level class decompiles to invoke scala.runtime.BoxesRunTime, but that's not in any of the scalac-net assemblies. On the up-side that would remove any nagging issues about CLR 2.0 compatibility, though; on the down-side, it would mean that I need a decompiler able to handle the generated code... Jode -- which I happened to have to hand -- balked at half the classes in the runtime; Jad seemed to have dealt with them all, though with a lot of goto statements replacing things like jumps out of loops -- but leaves a lot of JVM INSTR monitorenter;...JVM INSTR monitorexit; where a synchronized{} block should be, and possibly other horrors.

Meanwhile I took another prod at scalac-net, using the magic -Ydebug flag:

>\scala-2.6.1-final\bin\scalac-net -d classes -Xassem-path JavaLayer.dll SClass.
scala  -Ydebug
[running phase parser on SClass.scala]
[running phase namer on SClass.scala]
java.lang.ClassCastException: scala.tools.nsc.symtab.Symbols$ClassSymbol cannot
be cast to scala.runtime.Nothing$
        at scala.tools.nsc.symtab.clr.TypeParser.parseClass(TypeParser.scala:77)

        at scala.tools.nsc.symtab.clr.TypeParser.parse(TypeParser.scala:58)
        at scala.tools.nsc.symtab.SymbolLoaders$MSILTypeLoader.doComplete(Symbol
Loaders.scala:263)
        at scala.tools.nsc.symtab.SymbolLoaders$SymbolLoader.complete(SymbolLoad
ers.scala:54)
...
java.io.IOException: type 'scala.Predef' is broken
(scala.tools.nsc.symtab.Symbols$ClassSymbol cannot be cast to scala.runtime.Nothing$)
...

Kudos to the scala implementors -- the line numbers match up down the stack, and show the culprit to be

      unpickler.unpickle(symtab, 0, clazz.asInstanceOf, staticModule.asInstanceOf, typ.FullName);

which looks like it's doing the right sort of thing; and there's nothing particularly odd about the scala.Predef class in the assembly; and I get the same error trying to compile some of the examples in the distro...

Next diversion, rebuilding scalac with more instrumentation, piling the tower higher.

Wednesday, 30 January 2008

A tower of Babel

// JClass1.java
package com_ravnaandtines.jlayer;
public class JClass1
{
    public JClass1()
    {
    }
    public int doSomething(String arg)
    {
        System.out.println("In "+this.getClass().toString()+".doSomething(), printing "+arg);
        return arg.length();
    }
}
//SClass.scala
package com_ravnaandtines.slayer

import com_ravnaandtines.jlayer

class SClass(token: String) {
 private val in = new com_ravnaandtines.jlayer.JClass1()
 private val len = in.doSomething(token)
 Console.println(len)
}
//Python.py
import com_ravnaandtines.jlayer.JClass1

direct = com_ravnaandtines.jlayer.JClass1()
val = direct.doSomething("from Jython")
print val

import com_ravnaandtines.slayer.SClass
x = com_ravnaandtines.slayer.SClass("Hello Babel!")

Build the first into JavaLayer.jar and copy it alongside the second

\scala-2.6.1-final\bin\scalac -classpath .JavaLayer.jar -d classes SClass.scala
cd classes
"\Program Files\Java\jdk1.6.0\bin\jar.exe" -cf ..\ScalaLayer.jar .

Then run the last with the two jars and the scala runtime jar in your path

In class com_ravnaandtines.jlayer.JClass1.doSomething(), printing from Jython
11
In class com_ravnaandtines.jlayer.JClass1.doSomething(), printing Hello Babel!
12

I had hoped that I could do the same in .Net, but having built the J# JavaLayer.dll, I got

>\scala-2.6.1-final\bin\scalac-net -d classes -Xassem-path JavaLayer.dll SClass.
scala
error: error while loading Predef, type 'scala.Predef' is broken
(scala.tools.nsc.symtab.Symbols$ClassSymbol cannot be cast to scala.runtime.Noth
ing$)
one error found

so haven't yet managed to make a Scala-derived DLL for IronPython to consume. And that doesn't look like something I might obviously have done wrong.

Wednesday, 23 January 2008

Steps forwards, steps back.

It would be nice to have the getX()/setX() map to a property, syntactically, in general use Jython as well, along the lines of the previous essay. Alas, that simple "X indirects to getX()" method doesn't seem to work as is. I wonder if I'm relying on things that are a more modern version than Jython yet supports. I need to investigate more.

Meanwhile, on another front, even using the invaluable vjsresgen tool, I have to have platform specific interludes to handle resources -- especially to convert from .png format to something that the back-version Java support understands.

Colour me slowpoke ... Swing on J#

I'd not caught this before:

The Microsoft Supplemental UI Library provides much of the functionality described in the Java 2 JFC Swing specification. It also adds support for much of the functionality found in the JDK 1.2 java.util package.

Version 2.0 of the Supplemental UI Library is included as part of the Visual J# Version 2.0 Redistributable Package. No additional download is required.

To access the functionality in the Supplemental UI Library, simply add a reference to VJSSupUILib.dll in your project.

Betterer and betterer…

Of course this throws a little bit of a spanner in the works of the Jythonizer effort -- I might have subclassed javax.swing.JFrame, but not the component that I get from calling its shiny new contentPane attribute delegating to getContentPane(). Oh, well. At least I might be able to get some cute tricks along the lines of some of the ideas in Swing Hacks instead.

Tuesday, 22 January 2008

Making IronPython and J# more Jythonic -- Part 1

For the Nine Unknown Men who might also be attempting this sort of thing.

Persistance pays…

import dtai.gwt.GadgetFrame

def my__getattr__(self, name):
  if name.startswith("__"):
    raise AttributeError(name)
  getter = "get"+name.capitalize()
  if getter in dir(self):
    tmp = getattr(self, getter)
    return tmp()
  iser = "is"+name.capitalize()
  if iser in dir(self):
    tmp = getattr(self, iser)
    return tmp()
  raise AttributeError(name)
        
class Local:    
  def getFred(self):
    return "Fred!"
  
Local.__getattr__ = my__getattr__
   
test = Local()   
print test.fred

class WrappedGadgetFrame(dtai.gwt.GadgetFrame):
  pass

WrappedGadgetFrame.__getattr__ = my__getattr__
dtai.gwt.GadgetFrame = WrappedGadgetFrame

window =  dtai.gwt.GadgetFrame()
print window.visible

when executed, yields

C:...>PyInterop.exe
Fred!
False

which is the get() side of attributes done at the cost of a pass of subclassing. The equivalent set() shouldn't be too difficult, but automating the subclassing will be the next challenge.

Then adding the listener-based attributes; and finally, hiding it from Jython…

Monday, 21 January 2008

How Jythonic can it get?

Following up from my previous post, I've been thinking that it would be nice if I could make the code there a bit more Jythonic -- wrapping Java-style bean properties and event handlers transparently in the IronPython/J# world, where the inherent properties will be the Capitalized .Net ones, and we only have the .Net delegate-style handlers.

I will need to experiment to see exactly how open the IronPython proxy classes are to extension, first.

So many projects, so little free time. And I really need to do more with F# and PowerShell, not to mention wanting to try writing a generic protocol-terminating proxy framework in Erlang, probably with SOCKS5 as an exemplar protocol.

LATER

As I suspected, setting Local.__getattr__ = my__getattr__ for a function of suitable signature works where Local is a pure IronPython class; but for an imported .Net class I get


TypeError: can't set '__getattr__' in dictproxy

even with the indirect approach of something like dtai.gwt.GadgetFrame.__dict__["__getattr__"] = my__getattr__.

So Java/J# idioms at the interface it may have to be.

Wednesday, 16 January 2008

Pushing at an open door…

Compared with the travails required to shim Ruby.Net and JRuby onto a shared Java/J# code platform, doing the same for Jython (in NetBeans 5.0)/IronPython (using the DevStudio extension build for IronPython 1.1) was trivial. In fact most of the work was re-gearing my mind to Python after thinking in Ruby for some weeks.

Apart from the fact that that the IronPython build ignores any directory structure and smooshes all classes into the one assembly and considers that the package, which will impact on the broader code shape for any project, there is no shimming. Just build your assembly with references to the appropriate external files and you don't even need all the clr.AddReference to do it by hand

Doing the same as the J# and Ruby.Net — string and baling wire example, in a project that references the appropriate assemblies just requires the same Python code as a Jython build with the equivalent .jar files on the classpath

## pyinterop.py
import dtai.gwt.GadgetFrame
import java11.awt.event.WindowListener
import java.lang.System

window = dtai.gwt.GadgetFrame()
window.setSize (800, 600)
window.setTitle("Proof of Concept")

class Handler(java11.awt.event.WindowListener):
  def __init__(self, window):
    self.window = window

  def windowClosing(self, e):
    self.window.hide()

  def windowClosed(self, e):
    java.lang.System.exit(0)

  def windowActivated(self, e):
    pass

  def windowDeactivated(self, e):
    pass

  def windowDeiconified(self, e):
    pass

  def windowIconified(self, e):
    pass

  def windowOpened(self, e):
    pass

adapter = Handler(window)
window.addWindowListener(adapter)
window.show()

It still works in either case, if I simply use the WindowAdapter class and just override the methods I need. W00t! Indeed, so far it almost seem too easy!

Now I just have to keep working around the weird problems I ran into last time around this loop. Keeping Java beneath everything this time around should help.