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
const_missing
andmethod_missing
- Overload resolution happens in the method shims (a one time cost) to choose, e.g., which constructor to use for
System::Collections::ArrayList.new
- Integration is done to make the CLR feel more Rubyish
Implementation
This changes identity (proxied object):
ArrayList.new.as(IEnumerable)
This is less Rubyish, but identity is preserved:
IEnumerable.get_enumerator(ArrayList.new)
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.
I think John got a job @ Microsoft so he can continue it.
http://www.iunknown.com/articles/2006/10/20/dynamic-languages-microsoft-and-me
I updated that paragraph so that it’s not misconstrued as fact. But I did chat with John over the course of the weekend and that was the impression I got based on those conversations and after listening to his talk. I think MS would rather see Ruby as a full platform language ala IronPython, which is why they’re financially backing the Ruby.NET project.
Wow. Thanks for the great summary of my talk, Nick!
I’m wary about over-committing to RubyCLR with my other duties at MSFT. So hopefully someone will step up to take my place as the maintainer of RubyCLR so that it can continue moving forward.
The good news is that the code is in pretty good shape. The docs, on the other hand, could use some ... um ... writing :)