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

Tuesday 16 December 2008

More Silverlight Clock

I could, I suppose, have implemented this project in JavaScript -- that language has all the tools to get the current URL query string and set a permalink to a custom URL, one that wouldn't need clicking, but could be right-clicked; and save the self-inflicted DLR download hit.

If I wanted to, I could put the permalink URL out to an element in the DOM with Silverlight, too, which negates one perceived advantage. And using Silverlight gives me something extra -- multithreading.

Yes, there are JavaScript clocks, like this annoying mouse-following one, but they have to fake such things because they are running full-time in the UI thread. By using a BackgroundWorker to prompt a redraw at intervals (and, later, perform updates on the positions of celestial bodies), with Silverlight, I can offload everything but the painting from the UI thread.

Sunday 14 December 2008

Persisting user settings in Silverlight

Many years ago, the first GUI application I wrote (in X with Motif) was a little orrery-cum-clock thing, with the clock face doubling as a view of the sky, showing the classical planets. Some time in the intermediate past, I thought about doing this as a Java applet, but it never got anywhere, because out on the web, it would have to be settable to the user's geographic location, and I never figured a good way to persist that data between page visits.

Having done the basic tinkering with IronPython and Silverlight to get the two working together, I thought about resurrecting the project. And the first thing to solve is the settings persistence.

But now, I have an easy API to get at the current URL and such via System.Windows.Browser.HtmlPage.Document -- so I can read the values from its query string; and set the values in a hyperlink for bookmarking purposes, thus (app.py):

from System.Windows import Application
from System.Windows.Controls import Canvas
import System
import System.Windows.Browser

xaml = Application.Current.LoadRootVisual(Canvas(), "astroclock.xaml")
xaml.hyperlink.NavigateUri = System.Windows.Browser.HtmlPage.Document.DocumentUri
thisPage = System.Windows.Browser.HtmlPage.Document.DocumentUri.GetComponents(
  System.UriComponents.SchemeAndServer | System.UriComponents.Path,
  System.UriFormat.SafeUnescaped)
query = System.Windows.Browser.HtmlPage.Document.QueryString
  
try:
  xaml.slider1.Value = float(query['lat'])
except:
  pass
try:
  xaml.slider2.Value = float(query['long'])
except:
  pass
 
def latValueChanged(s, e):
  v = xaml.slider1.Value
  if v > 0:
 xaml.label1.Text = "Latitude %.2fN" % (v)
  elif v < 0:
 xaml.label1.Text = "Latitude %.2fS" % (-v)
  else: 
 xaml.label1.Text = "Latitude 0"
 xaml.hyperlink.NavigateUri = System.Uri("%s?lat=%f&long=%f" % (thisPage, v, xaml.slider2.Value))

xaml.slider1.ValueChanged += latValueChanged
latValueChanged(None, None)

def longValueChanged(s, e):
  v = xaml.slider2.Value
  if v > 0:
 xaml.label2.Text = "Longitude %.2fE" % (v)
  elif v < 0:
 xaml.label2.Text = "Longitude %.2fW" % (-v)
  else:
 xaml.label2.Text = "Longitude 0"
 xaml.hyperlink.NavigateUri = System.Uri("%s?lat=%f&long=%f" % (thisPage, xaml.slider1.Value, v))
 
xaml.slider2.ValueChanged += longValueChanged
longValueChanged(None, None)

driving some UI described by (astroclock.xaml)

<Canvas 
  x:Class="System.Windows.Controls.Canvas"
  xmlns="http://schemas.microsoft.com/client/2007"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="parentCanvas">
    <Grid>
        <Canvas Name="canvas1" Margin="0,0,0,129" Background="Black" Width="480" Height="240"/>
        <Slider Height="22" Margin="128,0,0,93" Name="slider1" VerticalAlignment="Bottom" Maximum="90" Minimum="-90" Value="52" LargeChange="10" SmallChange="1" Width="360"/>
        <TextBlock Height="28" Margin="0,0,0,87" Name="label1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="120">Latitude</TextBlock>
        <TextBlock Height="28" HorizontalAlignment="Left" Margin="0,0,0,62" Name="label2" VerticalAlignment="Bottom" Width="120">Longitude</TextBlock>
        <Slider Height="22" Margin="128,0,0,65" Name="slider2" VerticalAlignment="Bottom" Maximum="180" Minimum="-180" LargeChange="10" SmallChange="1" Width="360"/>
        <HyperlinkButton Height="28" HorizontalAlignment="Left" Margin="0,0,0,17" Name="hyperlink" VerticalAlignment="Bottom" Width="87" NavigateUri="astroclock.html" Content="Permalink" />
    </Grid>
</Canvas>

Evolving implementation here.

Tuesday 2 December 2008

Syntax highlighting

Following on from Scott Hanselman's post about the SyntaxHighlighter script, here's the secret sauce I needed to get it to work.

The separate hosting is the easy bit -- the trick was getting the code I needed to run the repainting into a window.onload, and to keep Blogger from mutilating the code by use of a CDATA section.

Et voilà!

<link href='.../SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script src='.../shCore.js' type='text/javascript'/>
<script src='.../shBrushPython.js' type='text/javascript'/>
<script src='.../shBrushRuby.js' type='text/javascript'/>
...
<script type='text/javascript'>//<![CDATA[
window.onload = function () {
    dp.SyntaxHighlighter.ClipboardSwf = ".../clipboard.swf";
    dp.SyntaxHighlighter.BloggerMode();
    dp.SyntaxHighlighter.HighlightAll("code",true,false,false,1,false);
}
//]]></script>

There is also a Scala brush for this -- but F# or Erlang will need to be hand-cranked first.

Later: hand cranking done & linked.

Saturday 29 November 2008

Python Swings; Ruby still doesn't

Here's a proof-of-concept of running a Swing UI from Python on the CLR and the JVM, following up on earlier experiments (which I had forgotten about).

try:  
  # IronPython must load the J# redistributable libraries  
  # Using the FullName of the assemblies is probably overkill  
  import clr  
  clr.AddReference( 'vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' )  
  clr.AddReference( 'vjssupuilib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' )  
except ImportError:  
  pass  
     
import javax.swing  
import java.awt.event  
import java.lang  
  
class Exit(java.awt.event.WindowAdapter):  
  def windowClosing(self, evt):  
    evt.getWindow().setVisible(False)
    evt.getWindow().dispose()
  def windowClosed(self, evt):  
    java.lang.System.exit(0) 
    
# With the 'import's above, we can now refer to things that are part of the  
# standard Java platform via their full paths.  
frame = javax.swing.JFrame("Window") # Creating a Java JFrame.  
label = javax.swing.JLabel("Hello")  
     
# We can transparently call Java methods on Java objects, just as if they were defined in Python.  
frame.getContentPane().add(label)  # Invoking the Java method 'getContentPane'.  
frame.addWindowListener(Exit()) # Need to do this for IronPython/J# which is barely JDK 1.2 level  
frame.pack()  
frame.setVisible(True)

which works happily with java -jar jython-complete.jar HelloSwing.py using Jython 2.5β0 and with ipy.exe HelloSwing.py for IronPython2.0RC2 as well.

I was briefly conflicted earlier this week when I saw that IronRuby had reached α2, and wondered about a JRuby/IronRuby UI, but the nigh-equivalent

begin  
  require 'vjslib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'  
  require 'vjssupuilib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'  
rescue LoadError  
  # This is the 'magical Java require line'.  
  require 'java'  
end    
        
class Exit < java.awt.event.WindowAdapter
  def windowClosing evt
    evt.getWindow.setVisible(false)
    evt.getWindow.dispose # make Closed
  end
  def windowClosed evt
    java.lang.System.exit 0 
  end
end

# With the 'require' above, we can now refer to things that are part of the  
# standard Java platform via their full paths.  
frame = javax.swing.JFrame.new("Window") # Creating a Java JFrame.  
label = javax.swing.JLabel.new("Hello")  
     
# We can transparently call Java methods on Java objects, just as if they were defined in Ruby.  
frame.getContentPane.add(label)  # Invoking the Java method 'getContentPane'.  
frame.addWindowListener(Exit.new()) # Need to do this for IronRuby/J# which is barely JDK 1.2 level  
frame.pack  
frame.setVisible(true)  

which works on JRuby 1.1.5, fails in IronRuby α2 when trying to load Swing classes, and I've not found a dodge that will get me at even class metadata for the Swing files. Ruby's casing rules may make it impossible for IronRuby to recognise the lower-case Java namespaces (I had fun with that earlier with Ruby.Net).

LATER: I could do something VM dependent that takes the class name and argument list for construction in {Iron|J}Ruby. What is more tricky is inheritance like

class Exit < java.awt.event.WindowAdapter

which is a major use-case. I wonder if there might be a metaprogramming technique I can use for this...

LATER YET: The problem is that there is no exposed mechanism to wrap a System.Type as a Ruby Class; I could manually subclass everything that is not final that I want in a C# assembly with a My.JavaNamespace and emulate the way that JRuby maps namespace Java::JavaAwtEvent to a value named java.awt.event, but the nearest to automation I can see is to Reflection.Emit a whole ton of stuff.

So, for the moment, consider it a dead end.

Sunday 19 October 2008

Sign of the times -- Impedence mismatch of Scala and J#

Following up on the Scala/.Net experiments, I took the interfaces for hashes and cyphers from my Java port; and replaced them in the Java world with a set of Scala traits, like:

trait MDA
{
    def update(data:Array[byte], offset:int, length:int): unit

    def update(data:byte) : unit

    def digest() : Array[byte] 
}

and it builds happily (though NetBeans 6.5 nightly complains it can't find the interface definition from the library in the code view).

Over to Visual Studio, with a suitable script to build the equivalent .dll -- and the implementing classes in J# fail to build because the Array[byte] maps to ubyte[] while a J# byte[] is an sbyte[], and so the J# compilation fails to match the signature of the Scala.Net trait -- and there's no Java ubyte type I can force everything to. And as byte arrays -- or at least bytes -- are the fundamental building block for streams, it looks like all the Java code has to get the elbow.

Thursday 25 September 2008

Why am I doing this sort of thing?

Michael Foord (aka Fuzzyman) has wondered, while linking me, about why one would want to talk to Scala from IronPython.

Partly, it is the intellectual challenge of that particular sub-problem. But the broader goal is to see how far it is possible, in this polyglot age, to build a language stack -- along the lines the Ola Bini mused about at the start of the year -- that one could drop onto the JVM or .Net using essentially the same code base, give or take a thin C# layer to provide compatible APIs in .Net to those needed in Java but not present in J#.

While the Fan language is developed to be exactly so code-compatible across the JVM and CLR, it appears to be resolutely monoglot, with the platform hidden behind an abstraction layer.

The ulterior motive is to take a codebase that I already have in Java/J#, the first stages of a reimplementation in a VM targeted language, of my old CTClib project -- and be able to complete the reimplementation/upgrade to RFC2440 spec, in a platform neutral way, and without having to write any more Java, even if the IronPython/J#+Swing interface will be rather less Pythonic than I could manage if I were just doing it in Jython.

And why Scala as well? For any new static layer code, especially where being explicit about the types involved, such as around the crypto, will make things clearer.

One correction, though, to the remarks : ATM, I'm using the scala-net compiler, which is part of the Scala bazaar, and seems (from its failure modes when the J# libraries are in the loop) to be a different generator to that in IKVM. Not being IKVM means I'm also spared having to drag in the GNU Classpath library, where the server stuff has priority, and desktop UI support is still primitive -- its AWT is less functional, in many important respects, than Java 1.0 was.

Wednesday 24 September 2008

Scaling the tower of Babel II

Finally, a little digital extraction. Scala from IronPython, works as expected. In file operator.scala:

package com_ravnaandtines.operator

trait Process {
 def op(x:Int, y:Int) : Int
}

class Multiply extends Process {
  def op(x:Int, y:Int) : Int =
   x * y
}

class Perform69 {
 def sixByNine(x: Process) =
  x.op(6,9)
}

Set up as in the previous post, and build using %SCALA_HOME%\bin\scalac-net.bat operator.scala to get operator.msil -- no assembly is generated at this point. Edit the .msil file as required to point at the appropriate versions of the runtime (see previous post). Then ilasm .\Operator.msil /dll /output=operator.dll. Now fire up IronPython:

>>> import clr
>>> clr.AddReference("operator.dll")
>>> from com_ravnaandtines.operator import *
>>> dir()
['Multiply', 'Perform69', 'Process', '__builtins__', '__doc__', '__name__', 'clr']
>>> m = Multiply()
>>> p69 = Perform69()
>>> p69.sixByNine(m)
54
>>> class Adder(Process):
...   def op(self,a,b):
...     return a+b
...
>>> add = Adder()
>>> p69.sixByNine(add)
15
>>>

So long as we get our interfaces/traits from Scala, all is fine.

In order to do the same in the JVM world, I need to have done set CLASSPATH=%CLASSPATH%;C:\scala-2.7.1.final\lib\scala-library.jar; and then I can do exactly as above, but without the first two lines with clr. Those I can put in a try/except, for common coding.

Note -- it is neither necessary nor sufficient to put the Scala library jar in java.class.path or python.path properties.

Saturday 23 August 2008

Scaling the tower of Babel

A few months ago, I was playing around with seeing how I could adapt an existing Java code base so that I could finish doing the work in better languages -- and have the code work on both the JVM and the CLR.

It seems that frustration will inevitably follow any attempt to incorporate any J# into the .Net versions of the stack (both IKVM and the Scala-net compilers bork when they see another Java in the stack) -- even though you can call Jython into Scala into Java on the JVM, this Tower of Babel cannot stand on the CLR with the J# runtime in the picture -- Java e.g. a Swing-based GUI using the J# extensions, has to stand off to one side.

That said, the Scala on .Net "hello world" with Scala 2.7.1 is comparatively painless.

  1. Install the scala-msil package (sbaz install scala-msil)
  2. Create file Hello.scala as
    import System.Console
    
    object test extends Application {
      Console.WriteLine("Hello world!")
    }
  3. In a Visual Studio command prompt, issue %SCALA_HOME%\bin\scalac-net.bat hello.scala
  4. Copy %SCALA_HOME%\lib\*.dll to the current directory
  5. Run the resulting test.exe

This uses the 1.0 version of mscorlib.dll; as a post-processing step you may wish to re-base against the .Net 2.0 version -- for this, you need to rebuild predef.dll and scalaruntime.dll using the same technique as needed to strong-name them after the fact; only this time you want to reset the mscorlib reference from

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 1:0:5000:0
}
to
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}

as well as doing any strong-naming you may desire.

To set the assembly name, add -Xassem [assembly name] to the compile command, to generate hello.exe.

To control the type of the generated assembly (.dll rather than .exe), I've not found a way other than taking the generated [assembly name].msil and ilasming it manually. In particular trying to skip generating the unwanted .exe will mean figuring why using scalac.bat -target:msil always gives

error: fatal error: class scala.runtime.BoxedBooleanArray not found.

whatever I do with -Xassem-path or tweaking environment variables.

Friday 8 August 2008

Integrating .Net with Erlang, part 8

Gratuitous update on 08/08/08 with a small increment of unit testing -- now using Rhino Mocks 3.4 as well as home-grown ones, and NUnit 2.5 (alpha 3) for the neat

Assert.That( [delegate expression], Throws.Exception<[type]>())
syntax.

Drop here, as usual.

Saturday 7 June 2008

Erlang and Python

Following the suggestion that I try TwOtp, I've tried the "kicking the tyres" with that library.

Adapting the sample code to work against my own local node seemed easy enough:

from twisted.internet import reactor
from erlang import OneShotPortMapperFactory, buildNodeName

def gotConnection(inst):
    return inst.factory.callRemote(inst, "file", "get_cwd"
        ).addCallback(gotResult)

def gotResult(resp):
    print "Got response", resp
    reactor.stop()

def eb(error):
    print "Got error", error
    reactor.stop()

epmd = OneShotPortMapperFactory('client@chloe.ravnaandtines.com', "cookie")
epmd.connectToNode("servernode@chloe.ravnaandtines.com").addCallback(gotConnection).addErrback(eb)
reactor.run()

which involves rather more baggage than using IronPython against my tidying of the C# port of jinterface, for just a "hello world!", given that the jinterface-derived "hello world!" actually does more work (passing arguments, testing results):

import clr
clr.AddReference("OtpErlang.dll")
from System import Array

from Tinesware.Otp import *
import Tinesware.Otp.Erlang as Erlang

cNode = Self("clientnode@chloe.ravnaandtines.com", "cookie")
sNode = Peer("servernode@chloe.ravnaandtines.com")
connection = cNode.Connect(sNode)

args = Array[Erlang.IObject]([Erlang.Integer(1), Erlang.Integer(2)])

connection.SendRpc("mathserver", "add", args)
sum = connection.ReceiveRpc()

if  sum.Value.ToInt32() != 3:
  print "Assertion failed, returned = " + sum.Value
else:
  print "OK!"

And, like py_interface, I find that this doesn't "just work" either:

C:\Documents and Settings\Steve\My Documents\code\babel\erlang>python twotphw.py

Got error [Failure instance: Traceback (failure with no frames): <class 'erlang.epmd.NodeNotFound'>: 1]

which will require a similar amount of rolling sleeves up and getting hands dirty to resolve.

Friday 6 June 2008

Erlang with Python and Ruby

Having played a bit with Erlang for real, in the sense of something non-trivial, even if not a complete product, I find I'm in the mood for more. But while it comes with some UI widgets, it's something more for headless use, and some client(s) in other languages doing the display.

To date, I can easily do Swing or WinForms as the UI toolkit -- but what about wxPython or FXRuby?

There are a number of bridges that I've found, but the closest to jinterface seem to be:

Neither of them have "just worked" for me in the way that the Java and C# versions have done against the simple mathserver example. Some of it might be down to my not figuring how the differences in the APIs are meant to work.

For py_interface, I had to comment out the line

[__import__(item) for item in __all__]
from init.py to get imports to work at all; and even then, the simple

from otp import *

def Handler(Result):
    print Result

cNode = erl_node.ErlNode("clientnode@chloe.ravnaandtines.com", erl_opts.ErlNodeOpts(cookie="cookie"))
print cNode
print cNode.Publish()
mBox = cNode.CreateMBox()
print mBox
mBox.SendRPC("servernode@chloe.ravnaandtines.com", 
    "mathserver", "add", [1, 2], Handler)
raw_input("wait")

just sits there; while the Ruby code

require 'erlang_node'
 
s_node = Erlang::Node.new("servernode@chloe.ravnaandtines.com")
c_node = Erlang::LocalNode.new("clientnode@chloe.ravnaandtines.com", "cookie")
connection = Erlang::Connection.new(s_node, c_node)
connection.sendRPC("mathserver", "add", [1,2])
sum = connection.receiveRPC()
puts "Fail" unless sum == 3

throws a different exception every time I run it, from some place or other inside the connection initializer.

So they both need deeper inspection than this simple kicking of the tyres, maybe modifying for R12 nodes, maybe just reverse engineering the kinks out of the driver programs.

Tuesday 27 May 2008

Integrating .Net with Erlang, part 7

Another update, after work during the holiday weekend.

By using a lot of spare cycles, I found a test case for the division code not previously exercised:

9659964175213286916418497243082984930780677040655778513759952405592597918851617939992802011783376153721017703858175 / 3248063261698017931917474008545947342556579729240422363527 = 2974068974926080862795323621370295193198999568425344221053

Also made the astoundingly obvious discovery that I needed the real Erlang port mapper dæmon running, so put a unit test in which spawns an Erlang process to contact. It works fine in NUnit-gui, but fails every time in the build time coverage plus test cycle, so is labelled as [Explicit]. I need to to write at least one test that handles the call in the other direction, but this is getting close to as far as can easily be done in unit test form.

And it's getting close to my usual summer break from coding in the evenings, so this is probably close to being "it" for a while.

Tuesday 20 May 2008

Integrating .Net with Erlang, part 6

Time for a major drop of the code.

It's been tidied up to remove most of the deprecation and to start unifying the comments as .Net XML. The BigInteger class has had a number of bugs found and fixed by unit testing (initialization, big left shifts, hex-string), and been made into a struct to reflect its value nature.

Pretty much all (say, 80%) of the stuff that can be tested statically in isolation has been, and the code has been revised with dependency injection and interfaces to do that (including a bug-fixed, back ported (to C# 2.0) version of NullObject.For<T>). Further testing will require some more extensive test set-up, such as spinning up a Java peer in a separate thread and talking TCP with it.

Code coverage is currently just over 60% for the Otp library, just over 70% for the ZLib code, for the static testing; beyond upgrading the wire types and the constants, the upgrade to 1.4 spec from 1.2 is not really begun.

Wednesday 23 April 2008

Integrating .Net with Erlang, part 5

I have a first drop that has all the C# input code written, and a start of some unit tests for interoperability with the J# build of jinterface 1.4. Nowhere near enough tests are written yet, and a couple of those that have been (encoding a 64-bit integer in J# and unpacking in C#) don't yet work. But at least it's a start.

Still to do are the full gamut of integer types, and the complex ones -- lists, tuples, ports and such, then replicate for writing by C# and reading in J#.

One fix to the tests was for my code -- I needed to take the surprising little-endian wire format for an extended integer, and reverse it to fit into the BigInteger class I got from Codeplex; the second was a fix to that class:

381c381,384
<    
---
> 
>             // BUGFIX -- use an accumulator rather than |=ing into
>             // m_digits[m_digits.DataUsed], which will be zero
>             DType accumulator = 0;
384c387,389
<     m_digits[m_digits.DataUsed] |= (DType)(array[offset + leftOver - i] << ((i - 1) * 8));
---
>                 DType digit = array[offset + leftOver - i];
>                 digit = (digit << ((i - 1) * 8));
>                 accumulator |= digit;
385a391
>             m_digits[m_digits.DataUsed] = accumulator;

Code drop for the curious at the usual site. The project assumes you have NCover and NUnit around your system to run the tests and take coverage stats.

Update: More tests, and a few more fixes, refactorings and extensions added 24-Apr. Doubles now get encoded in the new style and integers that fall into the Int64 range are handled so the jinterface code can handle them.

Update: 26-Apr -- Added an export to little-endian byte array for BigInteger and added unit tests for short and long BigInteger representations.

Update: 27-Apr -- A first pass of Java type to C# and back for all the Java wire types, and a start of interface breaking changes to shut FxCop up a bit. Still needs a lot of like-for-like based unit tests, and detailed code cleaning.

Update: 28-Apr -- Unit tests about complete for all the wire types. Now the fun really begins.

Update: 4-May -- Unit tests extended to the input and output classes, including adding compression via a modified version of the ComponentAce port JZlib. All code now clean after FxCop scrubbing. Still needs all the node related classes being compared with the jinterface 1.4 versions and tested.

Tuesday 22 April 2008

Integrating .Net with Erlang, part 4

So where are we going from here with the Otp.Net code? First off, if we bring the codebase into .Net 2.0 from its '04-'06 vintage, and make all the data classes in the Otp.Erlang namespace immutable -- returning ReadOnlyConnection(of T)rather than arrays as needed -- we can get rid of the ICloneable support. That lets us make Otp.Erlang.Object into an interface containing just the encode method(dropping the decode method, or making it an extension method as per C# 3.0).

Then we can use some subset of the fields used in equality tests to do GetHashCode properly, and replace arrays with growable collections.

Next, fix the range check on Double's floatValue method, and make it return a nullable value:

    public float? floatValue()
    {
        if (d > Single.MaxValue || d < Single.MinValue)
            return null;

        return (float) d;
    }

and rename Long as Integer, kill both their derived classes and make Integer carry a BigInteger to which we can delegate conversions returning nullables.

That will mean some fixing up of input and output, but we need that anyway to handle new-style float values encoded as 8-byte big-endian blobs (and the change of tense means that this is where we move past what I've done so far).

To come after that will be making GenericQueue delegate to Queue(of IObject), and then a general scrub done in comparison with jinterface 1.4, before it will be sorta-releasable.

At the moment it builds, but will not work, so no interim archive is yet publicly available.

Saturday 19 April 2008

Integrating .Net with Erlang, part 3

A kind anonymous has pointed out that someone has already done the job of porting an earlier version (1.2.1.1) of the jinterface code, even though it has not made its way into the standard distro. Via this blog post, one eventually gets to the sourceforge repository details for it.

This actually does work with IronPython (after the trivial edits to load the appropriate assembly and the slightly different class names) and without the J# runtime being involved.

I spotted the comment after spending a little while porting the 1.4 code. Actually the underlying Java code is quite horrid -- to start with there are lots of methods with the same name as fields; and a lot of identically named fields shadowing ones elsewhere in the inheritance hierarchy; and methods and fields are used interchangeably. Then there are blocks of cut-and-paste and tweak code; plenty of swallowing of exceptions and blurred responsibilities (where one object performs a series of manipulations on a member of another object). And there there is this (where d is a double):

  public float floatValue()
    throws OtpErlangRangeException {
    float f = (float)d;

    if (f != d) {
      throw new OtpErlangRangeException("Value too large for float: " + d);
    }

    return f;
  }

which doesn't look too tested to me -- what's this (f != d), in case you couldn't spot it. This is carried over into otp.net, and, I think, shows how little floating point is used.

I fixed up the name clashes and some of the blurred responsibility in the Java, then ran the conversion over; and by taking out the BigInteger stuff (not there in otp.net's Long class -- haven't checked the rest of these), compression, most of the floating point, got what was left to build, though it currently fails in the challenge/response handshake (where otp.net has replaced the roll-your-own MD5 with calls into System.Cryptography).

Where could we go from here?

Two main things need doing. The otp.net code needs to be brought up to the 1.4 standard and make better use of .Net 2.0 e.g. for tracing; and it needs to be refactored to clean up inherited code smells.

Ideally, some of the changes should be back-ported into jinterface, too.

To date, this includes fallback to Java's file based location for cookie and a replacement for some of the non-ported tracing code (logging the remote endpoint).

Friday 18 April 2008

Integrating .Net with Erlang, part 2

So, we have pure J#. Where do we go from here?

C#

The body of the driver class carries over unchanged but for the Exception type. The driver project has to itself reference vjslib, as well as the jinterface assembly but is otherwise a standard C# class-with-main, and "just works".

using System;
using com.ericsson.otp.erlang;

public class ClientNode
{
 
 [STAThread]
 public static void  Main(System.String[] _args)
 {
  
  OtpSelf cNode = new OtpSelf("clientnode", "cookie");
  OtpPeer sNode = new OtpPeer("servernode@chloe.ravnaandtines.com");
  OtpConnection connection = cNode.connect(sNode);
  
  OtpErlangObject[] args = new OtpErlangObject[]{new OtpErlangLong(1), new OtpErlangLong(2)};
  connection.sendRPC("mathserver", "add", args);
  OtpErlangLong sum = (OtpErlangLong) connection.receiveRPC();
  if (sum.intValue() != 3)
  {
   throw new System.SystemException("Assertion failed, returned = " + sum.intValue());
  }
  System.Console.Out.WriteLine("OK!");
 }
}

How do we divest ourselves of the dependency on the J# runtime?

The Java Language Conversion Assistant generates C# code that doesn't compile, and would require a moderate amount of patching up for differences between superficially similar API classes. It is by no means a one evening exercise.

The OtpErlang.jar similarly fails to be converted by the jbImp tool, but IKVM converts it nicely; so at the penalty of having 27Mb worth of IKVM.OpenJDK.ClassLibrary.dll and IKVM.Runtime.dll instead of 3.7Mb of J#, driving the ~100kb dll, you can build the C# program and it passes this simple proof of concept.

IronPython and the DLR

Porting the code is easy enough

import clr
clr.AddReference("jinterface.dll")
from System import Array

from com.ericsson.otp.erlang import *

cNode = OtpSelf("clientnode", "cookie")
sNode = OtpPeer("servernode@chloe.ravnaandtines.com")
connection = cNode.connect(sNode);

args = Array[OtpErlangObject]([OtpErlangLong(1), OtpErlangLong(2)])
connection.sendRPC("mathserver", "add", args)
sum = connection.receiveRPC()
if (sum.intValue() != 3):
  print "Assertion failed, returned = " + sum.intValue()
else:
  print "OK!"

A direct conversion, the only slightly tricky bit being coercing the list to an Array.

This works fine when calling into the J# built library, as expected. IKVM needs the latest version -- before 0.36.0.11 (see comments), though, is a different story.

>\IronPython-2.0B1\ipy.exe Program.py
Traceback (most recent call last):
  File Snippets, line unknown, in Initialize
  File OtpErlang, line unknown, in connect
  File OtpErlang, line unknown, in .ctor
  File OtpErlang, line unknown, in .ctor
  File IKVM.OpenJDK.ClassLibrary, line unknown, in .ctor
  File IKVM.OpenJDK.ClassLibrary, line unknown, in init
  File IKVM.OpenJDK.ClassLibrary, line unknown, in getContext
  File IKVM.OpenJDK.ClassLibrary, line unknown, in getStackAccessControlContext
  File IKVM.Runtime, line unknown, in getStackAccessControlContext
  File IKVM.Runtime, line unknown, in GetProtectionDomainFromType
  File IKVM.Runtime, line unknown, in getProtectionDomain0
  File IKVM.Runtime, line unknown, in GetProtectionDomain
SystemError: The invoked member is not supported in a dynamic assembly.

Trace taken with 0.36.0.5, from last December. Fortunately, that wasn't some fundamental architectural thing being run into.

Integrating .Net with Erlang, part 1

So, you can integrate Java with Erlang, using the jinterface code supplied as part of the standard Erlang distribution. It's Java, so can we do this with .Net?

Let's start with J#. We set up the erlang source

-module(mathserver).
-export([start/0, add/2]).

start() ->
   Pid = spawn(fun() -> loop() end),
   register(mathserver, Pid).

loop() ->
   receive
      {From, {add, First, Second}} ->
        From ! {mathserver, First + Second},
        loop()
   end.

add(First, Second) ->
   mathserver ! {self(), {add, First, Second}},
   receive
      {mathserver, Reply} -> Reply
   end.

and test it with

>erl -name servernode@chloe.ravnaandtines.com -setcookie cookie
Eshell V5.6  (abort with ^G)
(servernode@chloe.ravnaandtines.com)1> node().
'servernode@chloe.ravnaandtines.com'
(servernode@chloe.ravnaandtines.com)2> pwd().
jinterface          mathserver.erl
ok
(servernode@chloe.ravnaandtines.com)3> c(mathserver).
l{ok,mathserver}
(servernode@chloe.ravnaandtines.com)4> s().
jinterface          mathserver.beam     mathserver.erl
ok
(servernode@chloe.ravnaandtines.com)5> mathserver:start().
true
(servernode@chloe.ravnaandtines.com)6> mathserver:add(1,2).
3
(servernode@chloe.ravnaandtines.com)7>

Now fire up Visual Studio, and create a J# class library project. Add existing items to copy the jinterface code into the project, and build it.

Cannot find type 'java.lang.ref.WeakReference'

Well, that's not too bad. Give it a stub, and build again:

package java.lang.ref;
import System.*;

public class WeakReference extends System.WeakReference
{
    public WeakReference()
    {
    }
}

gives us

error VJS1227: Cannot find constructor 'java.lang.ref.WeakReference(com.ericsson.otp.erlang.OtpMbox)'
error VJS1223: Cannot find method 'get()' in 'java.lang.ref.WeakReference'

So give it what it needs:

package java.lang.ref;
import System.*;

public class WeakReference extends System.WeakReference
{
    public WeakReference(Object o)
    {
        super(o);
    }
    public Object get()
    {
        try
        {
            return this.get_Target();
        }
        catch (InvalidOperationException ioe)
        {
            return null;
        }
    }
}

And it builds. Now put in the driver program:

import com.ericsson.otp.erlang.*;

public class ClientNode
{

    public static void main(String[] _args) throws Exception
    {

        OtpSelf cNode = new OtpSelf("clientnode", "cookie");
        OtpPeer sNode = new OtpPeer("servernode"+"@"+"chloe.ravnaandtines.com");
        OtpConnection connection = cNode.connect(sNode);

        OtpErlangObject[] args = new OtpErlangObject[]{
            new OtpErlangLong(1), new OtpErlangLong(2)};
        connection.sendRPC("mathserver", "add", args);
        OtpErlangLong sum = (OtpErlangLong)connection.receiveRPC();
        if (sum.intValue() != 3)
        {
                throw new IllegalStateException("Assertion failed, returned = " + sum.intValue());
        }
        System.out.println("OK!");

    }

}

Now, run that and get:

OK!

So, we have first light!

Get the goodies from here.

Tuesday 8 April 2008

Blast from the past

I had need to play with .ico files for the first time in ages the other day, and pulled out my old Java IcoImage utility to start with -- only to realise that it didn't handle modern 32-bit depth icons.

So I fixed it.

Latest versions here.

Tuesday 19 February 2008

PassiveFTP 1.11

Here or here.

PassiveFTP 1.11 — build 1.11.2971.37821 — mitigates the upload rate problem I've been having, by doing some unexpectedly effective tweaks to socket parameters.

This came after having do do some throughput optimizations on XP at work for code that worked just dandy on Windows server OSs from NT4 up. There it was just a case of upping the send buffer size. Here, that was ineffective, but I did get a big boost from by sending only small packets and disabling Nagle coalescence.

The new default upload rate is 128kb/s (1ms sleep between successful sends of 128-byte packets), which gave the best rate for me, up from an old and unreliable 2kb/s.

This will of course feed back into the FePy version whenever I get the enthusiasm for doing all the plumbing.

Monday 4 February 2008

If only...

Ultimately, the big splat from yesterday tracks down to calling the stub of


JbImp error: Couldn't find class 'java.lang.InheritableThreadLocal'

from the class constructor of Console$. Now it would not be beyond the wit of man to emulate that new class in a library shim and leave everything else as I found it, but... More annoying are the extensions to fundamental classes dating back to JDK 1.0 days, especially final ones like String


JbImp error: Unresolved Method 'public static java.lang.String java.lang.Character.toString(char)'
JbImp error: Unresolved Method 'public static java.lang.String[] java.lang.String.split(java.lang.String)'

where (absent some incantation to splice J#'s AWT into the namespace of an OpenJDK dll or similar), tackling it means modifying the Scala library code to retrofit. Oh, yes, and even then there are some places where the Scala bytecode manages to throw jbimp for a wobbly.

But if I keep to a fairly restricted subset (and for the moment I'd be interested in using it when writing a parser of OpenPGP), I might get away with a very small port of the runtime and library.

Oh, well, like I said, hands on.

Sunday 3 February 2008

Under my nose all the time

Another of those hidden things about J# -- the JbImp tool, which takes .class files and spits out J# assemblies. Just what I wanted, but was looking in the general freeware community for.

Now the full scala-library.jar has a lot of post-J# Java API calls, but by cutting out a lot of the code I can get

>"\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\Jbimp.exe" /t:library /usestubrefs /out:scala-lib.dll /recurse *.class

to work on the remainder of it, and then

>"\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\Jbimp.exe" /t:library /usestubrefs /r:..\JavaLayer.dll ..\scala-lib.dll /out:SClass.dll /recurse *.class

And then build an IronPython project against it and get…

>PythonLayer.exe
In class com_ravnaandtines.jlayer.JClass1.doSomething(), printing from Jython
11
In class com_ravnaandtines.jlayer.JClass1.doSomething(), printing Hello Babel!
Traceback (most recent call last):
  File scala-lib, line unknown, in .cctor
  File vjslib, line unknown, in checkAndThrowException
  File src\Program.py, line 24, in Initialize
  File , line 0, in NonDefaultNew##27
  File , line 0, in .ctor##29
  File SClass, line unknown, in .ctor
SystemError: The type initializer for 'scala.Console$' threw an exception.

which is progress, and most of what the JVM version does; but as this

    private int len;
    private JClass1 in = new JClass1();

    public SClass(String token)
    {
        len = in().doSomething(token);
        Console$.MODULE$.println(BoxesRunTime.boxToInteger(len()));
    }

is the relevant part of the SClass code decompiled, the failure means that although it has executed some Scala derived code, it has fallen over at the first sniff of runtime.

I hope that a more measured winnowing of the runtime will fix this. But not tonight.

No love for client-side Java

It seemed a nice idea, having a deeper stack than just Python on Java that could build cross-VM apps from one code-base. But alas…

  • The only Java-on-.Net runtime I've found that has even half-way decent support for client-side apps (enough of AWT to support the GWT, or any flavour of Swing) is MSFT's J#, especially at 2.0
  • The obvious cross-compilers (scala-net, if I could get it to work; IKVM) want to use anything else they can except the J# runtime, and don't offer the facility to choose the one you want
  • Meanwhile scala's bytecode is just plain beyond decompilation to Java by obvious decompilers

So, I'd have to write the tools myself if I want to do this. It wouldn't even be a simple fork of IKVM to re-point references, and there are also its own special attributes decorating the classes. It might be simpler to tweak the scala compiler, since the .Net-bit islooked smaller in that (and it would improve my hands-on with the language).

 

Later:

Building a replacement scalaruntime.dll based on the .Java files from the scala-library source jar (one tweak for the older Java dialect with doesn't have the JDK 1.4 Character.toString()), plus a J# version of scala.runtime.SymtabAttribute based on the C# one in SVN, easy. Finding that the scala compiler source jar omits all the MSIL compiler files (from https://lampsvn.epfl.ch/trac/scala/browser/msil/trunk), more of a pain.

With a mscorlib 2.0 and my new runtime, and the predef.dll moved out of the way, I have to figure out why System.String is causing a wobbly:


java.lang.RuntimeException: PEModule.getTypeDefOrRef(): TypeSpec
        at ch.epfl.lamp.compiler.msil.PEModule.getTypeDefOrRef(PEModule.java:206)
        at ch.epfl.lamp.compiler.msil.PEType.loadInterfaces(PEType.java:309)
        at ch.epfl.lamp.compiler.msil.Type.initInterfaces(Type.java:944)
        at ch.epfl.lamp.compiler.msil.Type.getInterfaces(Type.java:907)
        at scala.tools.nsc.symtab.clr.TypeParser.parseClass(TypeParser.scala:88)
        at scala.tools.nsc.symtab.clr.TypeParser.parse(TypeParser.scala:58)
...
java.io.IOException: type 'System.String' is broken

I'd probably have to rework a whole lot of stuff that shims a virtual Java library layer. Which would have to start with identifying and encapsulating the shimming.

Friday 1 February 2008

One step forwards...

Based on the helpful comment on my last post, I can run IKVM against 2.0 assemblies, but hit a different obstacle -- a critical failure linking against the J# runtime, leading to a bug report.

It seems to run OK auto-binding to the OpenJDK, but then I need to frob the reference somehow. Perhaps it is back to the scala-net class loader issue...

Le sigh

Later...

I wondered. We won't have much of Swing, but do we have enough of AWT to run the GWT? So I converted TestGadget.jar and gwt221.jar and put all the images and .dlls into the same folder and ran it and...

>TestGadget.exe
Exception during event dispatch:
cli.System.NotImplementedException: The method or operation is not implemented.
        at cli.ikvm.awt.NetComponentPeer.createImage(Unknown Source)
        at java.awt.Component.createImage(Component.java:2522)
        at dtai.gwt.Gadget.createImage(Gadget.java:2045)
        at dtai.gwt.ImageGadget.validateImage(ImageGadget.java:255)
        at dtai.gwt.ImageGadget.paintForeground(ImageGadget.java:283)
...

and while much of the applet showed, the (re-)paint behaviour was terrible, and the applet could easily get into a state where it was spinning at almost 100% CPU.

Le sigh²

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.

Tuesday 15 January 2008

Ruby.Net and Ruby.Net — foiled again

A reboot (of the machine, and myself) later, I realised that the obscure "Wrong argument type String (Class expected)" was the result of a sleep-addled 'C'-drenched brain putting include 'Wizard' where require 'Wizard' was expected.

Not so good with the memory issue. After a couple of hours debugging and finally getting the code to interoperate, DevStudio was peaking at over 370Mb of memory, and still thrashing (on a 512Mb machine), while building a project with < 1000 lines of Ruby. NetBeans, by comparison has about 150Mb (if I have a lot of files open)in the IDE and and under 40Mb in the spawned application.

I've put the Interop example code -- showing how to call from shared code JRuby/Ruby.Net to shared-code Java/J# libraries. main.rb calls Wizard.rb which calls through the interop layer defined by .jsl files for Ruby.Net->J#, and Interfaces.rb plus the .java files for JRuby->Java -- on one of my sites, for those who are interested in taking this further.

Until I upgrade my hardware to something that permits more than a toy Ruby.Net layer, though, I don't think I'll be taking the ideal of a shared code/multi-VM project further with Ruby. Which sucks, because that has the best IDE support (I don't even know if the Jython add-in for NetBeans still works at 6.0).

Still a little experimentation is needed with that, and with Scala, to get to an equivalent proof of concept stage.

Monday 14 January 2008

Ruby.Net and Ruby.Net — first steps

Not a typo, alas.

I was testing calling from a Ruby.Net .exe file into a Ruby.Net .dll, to see if partitioning like that would work; though not in such a simple setup as that : I was trying to test a Ruby implementation of a wizard dialog using the GWT... So I create a Testbed.Net.exe that refers to gwt_ruby.dll (which is built from a single source file Wizard.rb).

That fails with a Key Not Found Exception, and looking at the Ruby.Net code, and ildasm-ing the assembly, I discern that it was looking for a gwt_ruby.rb file having been built into the project. So I give it one to satisfy it

require 'Wizard'
class Gwt_Ruby
end

Later...

The Ruby.Net build is being a voracious memory hog on my 3 year old machine with only 512Mb RAM -- even for only a few hundred lines of Ruby code each build and test is taking more than half an hour of thrashing madly at almost 0% CPU. And I thought that NetBeans was memory hungry -- that I can work on in realtime, with the same code in JRuby. I'm not sure that testing this is going to be practical, even without having to work around packaging quirks.

It's almost enough to drive me to Scala!