RubyConf: Your Ruby in My CLR
Posted by Nick Sieger Mon, 23 Oct 2006 14:16:00 GMT
John Lam wanted to build a photo-flash-card application using Avalon and Indigo and Flickr, but also using Ruby as the implementation language. So along the way he decided to build an interop layer (a bridge) between Ruby and the CLR to do it.
Now that John has joined Microsoft, his new mission (bigger picture) is to further dynamic language implementations on the CLR.
Bridging type systems
Dynamic methods in the CLR allow you to do better than simply invoking the reflection API.
Ruby | C | CLR ============================================ shadow class | dynamic method | instance
Polymorphic inline caching -- caching method dispatches on different call sites based on the assumption that types don’t change that often
- Generate shadow classes and method stubs using
- Overload resolution happens in the method shims (a one time cost) to choose, e.g., which constructor to use for
- Integration is done to make the CLR feel more Rubyish
This changes identity (proxied object):
This is less Rubyish, but identity is preserved:
There are trade-offs and warts to a bridge approach to Ruby integration on top of a platform such as the CLR: there is a need to inject artificial type information occasionally to be able to construct CLR objects (e.g., arrays --
Array.of(Int32).new(3)). Generics are evil! Simple stuff doesn’t seem so bad:
List.of(Int32).new, but there’s more pain to be had (see John for details). John also built a RubyInline-like implementation for the CLR languages too, to allow for getting things done (even if it’s dirty). Finally, method overloading is a problem, especially when there is no equivalent Ruby type -- this gave way to
instance_shim which is a sort of aliasing method that mixes in type metadata for use by the interop layer.
On the other hand, there are many places where Ruby (even in bridged mode) can make the experience of developing on the CLR better. Implementing CLR interfaces is a feature that allows Ruby objects to cross to the CLR side, (e.g., adding IEnumerable to Ruby Array). Performance across the CLR boundary (marshalling data) is ~100 times slower than C#, but still fast (3 million calls/second). Huge benefits are gained from using DSLs in Ruby to help with the implementation of the interop layer. Also, RubyCLR allows mixing in methods into CLR types, so we can re-skin APIs that feel clunky in Ruby. This is really leveraging the power of Ruby in the best possible way.
My take is that it looks like the RubyCLR project will probably not be seeing much further development, unless John finds a willing maintainer -- but this is speculation, I haven’t confirmed with John. Yet, the problem of impedance matching between type systems is a recurring theme in the dynamic language arena, and so John’s work is valuable in helping us to understand this issue.