« February 2006 | Main | April 2006 »

March 2006

March 31, 2006

RubyCLR now resolves types in top-level namespaces

Up until now, RubyCLR did not support finding types in the top-level (global) namespace. If you were writing code that used types in the global namespace (which you will if you don’t scope things by namespace – typically for your own libraries), it wouldn’t work correctly.

I had punted on this bug for a while but finally had to fix it when I added JScript.NET compilation support to RubyCLR today. JScript.NET does not support declaring types in namespaces (as far as I can tell – I’m by no means a JScript.NET dev).

It required refactoring how I handled the boundary case of a type that wasn’t scoped by a Ruby Module.

So this code finally works:


inline :jscript do |compiler|
  compiler.compile <<-EOF
    class JScriptClass {
      function sayHello() {
        return "hello" 
      }
    }
  EOF
end

def test_inline_jscript
  assert_equal 'hello', JScriptClass.new.sayHello
end

March 30, 2006

RubyCLR, now with new and improved inlining

Thanks to Eric Hodel and Ryan Davis for pointing me to RubyInline for yet another source of inspiration.

I first saw RubyInline at last years’ RubyConf – it’s a remarkable piece of code that lets you drop inline C into your Ruby programs. However, I don’t really need most of the features in RubyInline since the managed CSharpCodeProvider class already does most of what they do (and a bit more), and RubyCLR does the rest (handling marshaling of parameter types).

However, I did look at their implementation and lifted how they added an inline method to the Module class, and yielding a block that contains the correct compiler wrapper.

The current implementation now does both C# and VB.NET code (and I’ll add support for JScript.NET once I ship this blog entry). Here’s how it looks now:


class InliningTests < TestCase
  inline :csharp do |compiler|
    compiler.reference('System.Windows.Forms.dll')
    compiler.compile <<-EOF
      namespace Scratch {
        public class Fibonnaci {
          public static long Calc(long n) {
            long x1 = 1, x2 = 2, tmp;
            for (long i = 1; i < n; ++i) {
              x1 += x2;
              tmp = x2; x2 = x1; x1 = tmp;
            }
            return x1;
          }
          public static void SayHello() {
            System.Windows.Forms.MessageBox.Show("Hello, World!");
          }
        }
      }
    EOF

    inline :vb do |compiler|
      compiler.compile <<-EOF
        Namespace VBScratch
          Public Class Fibonnaci
            Public Shared Function Calc(n As Long) As Long
              Dim x1 As Long = 1
              Dim x2 As Long = 2
              Dim tmp As Long
              Dim i As Long
              For i = 1 To n - 1
                x1 = x1 + x2
                tmp = x2
                x2 = x1
                x1 = tmp
              Next
              Return x1
            End Function
          End Class
        End Namespace
      EOF
    end

    def test_csharp_inline    
      assert_equal 8, Scratch::Fibonnaci.calc(5)
      assert_equal 8, VBScratch::Fibonnaci.calc(5)
    end
  end
end

Notice how I can add references to external assemblies as well via compiler.reference.

So please disregard the implementation that I posted yesterday :)

March 29, 2006

RubyCLR can now inline C#

RubyCLR now inlines C#:


class InliningTests < TestCase
  def test_class_inline
    Inline::compile :csharp, <<-EOF
      namespace Scratch {
        public class Fibonnaci {
          public static long Calc(long n) {
            long x1 = 1, x2 = 2, tmp;
            for (long i = 1; i < n; ++i) {
              x1 += x2;
              tmp = x2; x2 = x1; x1 = tmp;
            }
            return x1;
          }
        }
      }
    EOF

    assert_equal 8, Scratch::Fibonnaci.calc(5)
  end
end

I shell out to the C# compiler to compile the embedded C# source code. I’ll be adding some code to inline C# methods as well so that you can define a Ruby method signature that has a C# implementation.

Update: Please disregard this grotesque hack. See the new and improved version.

Interface implementation in RubyCLR

Over lunch today I hacked out a quick first pass at defining a dynamic type that understands how to implement the IDisposable interface. In a nutshell, RubyCLR will define an “anonymous type” in a dynamic assembly that maps to its corresponding Ruby class object. I’ll generate this dynamic type on the fly and marshal Ruby objects to the CLR as instances of that type (this is a gross simplification, but bear with me). This way Ruby objects can implement arbitrary CLR interfaces, and I can also provide mixin implementations for common ones like IDisposable or IBindingList.

Here’s the quick and dirty C# implementation that demonstrates how to make this happen:


static Type CreateBindableObject() {
  AppDomain currentDomain = AppDomain.CurrentDomain;

  AssemblyName assemblyName 
    = new AssemblyName("AnonymousRubyInteropAssembly");

  AssemblyBuilder assemblyBuilder 
    = currentDomain.DefineDynamicAssembly(assemblyName, 
                                          AssemblyBuilderAccess.Run);
  ModuleBuilder moduleBuilder 
    = assemblyBuilder.DefineDynamicModule("AnonymousRubyInteropModule");

  TypeBuilder typeBuilder 
    = moduleBuilder.DefineType("AnonymousInteropShim", 
                               TypeAttributes.Public);

  typeBuilder.AddInterfaceImplementation(typeof(IDisposable));

  MethodBuilder methodBuilder 
    = typeBuilder.DefineMethod("Dispose", 
                               MethodAttributes.Public 
                               | MethodAttributes.Virtual, 
                               typeof(void), 
                               new Type[] { });

  ILGenerator g = methodBuilder.GetILGenerator();

  Type consoleType = typeof(Console);
  MethodInfo mi = typeof(Console).GetMethod("WriteLine", 
                                            new Type[] { typeof(string) });

  g.Emit(OpCodes.Ldstr, "Disposed!");
  g.Emit(OpCodes.Call, mi);
  g.Emit(OpCodes.Ret);

  return typeBuilder.CreateType();
}

static void Main(string[] args) {
  Type t = CreateBindableObject();
  using (IDisposable obj = (IDisposable)Activator.CreateInstance(t)) {
    Console.WriteLine("using object");
  }
}

I would imagine that RubyCLR will eventually support a syntax that looks like:


class DisposableRubyObject
  implements IDisposable

  def dispose
    Console.write_line 'disposed!'
  end
end

where the implements method is some syntactical sugar around include.

This should make it much easier for me to support data binding scenarios. The current databinding stuff is all hard-coded, and this technique is far more flexible.

Vote for Ruby and .NET BOF at Tech Ed 2006

Scott Hanselman and I are co-hosting a Ruby and .NET Birds-Of-A-Feather session at Tech Ed this year. Make sure you vote for it this week if you want to see it happen.

Thanks!

reference_file bug in third drop of RubyCLR

I just found a bug in RubyCLR that could potentially break the way enumerations (and potentially generic types) are handled. If you call RubyClr::reference_file more than once for the same assembly, I’ll parse the assembly more than once (this is the bug).

Here’s a patch that will fix this bug. You’ll need to replace the method body for reference_file in core.rb.


def self.reference_file(assembly_path)
  @@assembly_filenames ||= []
  if @@assembly_filenames.include?(assembly_path)
    false
  else
    generate_modules(internal_reference_file(assembly_path))
    @@assembly_filenames << assembly_path
    true
  end
end

Yes, I’m working on getting the source loaded into rubyforge, but I need to carve out some time to make that happen.

Please let me know if you have any problems with the bridge. jlam at this domain or via the comments.

March 28, 2006

Looking back at some older Ruby .NET bridges

I just spent some time looking around at past attempts to write Ruby to .NET bridges. Here’s a fascinating thread from July, 2003 that was started by Thomas Sondergaard who wrote an excellent Ruby to .NET bridge. His bridge provided much inspiration for the first version of RubyCLR which was never publicly released.

I learned a lot writing that first bridge, and the pain that I felt implementing everything in C+++/CLI was enough to inspire the current RubyCLR bridge which uses as little C+++ as possible.

DemoCamp 4

Wow. The Toronto-based startup community is absolutely thriving. I had a break from evening baby-duty tonight so I attended the 4th iteration of the DemoCamp. As you can see, over 150 people showed up for this event, which featured some really interesting demos.

I’ll have to demo the next iteration of RubyCLR there …

March 27, 2006

RubyCLR World Tour shaping up

Things are looking good for RubyCLR. The first two stops in this summers’ RubyCLR world tour are now confirmed: Tech Ed 2006 in Boston the week of June 12, and the O’Reilly Open Source Convention 2006 the week of July 24.

I’ll be sharing the stage at Tech Ed with Mahesh Prakriya, who is the CLR PM in charge of dynamic languages.

Looks like it will be a good summer of love for RubyCLR. Hope to meet some of you there!

March 23, 2006

A few quick observations

IE7 finally renders my blog correctly! You can get it here.

I’ve been pretty disappointed with Firefox 1.5 recently – I just killed it when memory consumption hit 300MB an hour ago. I still need my Firefox extensions though, so I’ll keep it around, but I suspect I’ll be spending a bit more time in IE7 for the next little while.

I’ve been spending a lot of time using Komodo as my Ruby text editor. I love the tabbed editing, the project browser, and the reasonable Intellisense support. Eric Promislow has already fixed the string inline expression syntax highlighting bug, but we’ll all have to wait for a packaged release to get this last feature that ruby-mode in emacs has over Komodo.

Eric Hodel pointed me to parsetree, which is a Ruby C extension that lets me serialize Ruby’s AST (apparently with limitations). I’ve been thinking about writing some code to improve how irb behaves, and serializing the AST might be a first step in that project.

Photos

  • www.flickr.com
    This is a Flickr badge showing public photos from John Lam. Make your own badge here.

Recent Comments

Recent Posts

May 2008

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Blog powered by TypePad