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

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.

2 comments:

Jeroen Frijters said...

This problem has been fixed in IKVM 0.36.0.11.

Steve said...

Super! That's what I get for not having updated since the the end of last year (still on 0.36.0.5 here).