MountainWest RubyConf 2007
Ruby CLR and Ruby.NET

Ruby CLR and Ruby.NET

by John Lam

In the video titled 'Ruby CLR and Ruby.NET,' John Lam, a Microsoft employee, discusses his journey and the technical aspects of enabling Ruby to interoperate with .NET through the Ruby CLR bridge. John shares his transition from living in Toronto to Seattle, where he joined Microsoft to work on dynamic languages, specifically Ruby. He begins by elaborating on the challenges of running Ruby on platforms such as the CLR or JVM, highlighting the importance of accessing existing libraries on these platforms. Key points covered include:

  • Dynamic Language Interoperability: John explains the complexities of allowing Ruby to work with .NET libraries, emphasizing that the experience should remain natural for Ruby developers.
  • Cultural Differences: He notes the distinctions between the Ruby and Python communities, affecting design decisions in the interoperability efforts.
  • Technical Insights: John discusses the use of Reflector, a tool for exploring .NET metadata, and how it aids in understanding code interoperability. He highlights how dynamic methods in CLR optimize the execution process and support memory management.
  • Ruby CLR Implementation: The Ruby CLR allows for the creation of proxy classes, enabling method calls between Ruby and CLR libraries. John discusses the integration of CLR types with Ruby syntax, using examples like ArrayList to demonstrate intuitive object manipulation.
  • Method Overloading Challenges: The presentation addresses difficulties with method signatures and type resolution between Ruby and CLR, advocating for clarity in method definitions to enhance user experience.
  • Future Exploration: John concludes by encouraging further exploration of Ruby CLR, hinting at ongoing developments and community efforts to address compatibility issues, especially for different platforms like Mono.

Overall, the talk seeks to provide a comprehensive understanding of Ruby and .NET interoperability while reinforcing the natural usage of Ruby's dynamic features.

00:00:06.720 Hello everyone, thank you for coming today.
00:00:12.000 My name is John Lam, and I work for Microsoft.
00:00:18.359 I want to start off by sharing a little bit of my story and the journey that brought me to where I am today.
00:00:24.359 At the last RubyConf in October, I announced that I was joining Microsoft to work on dynamic languages.
00:00:30.000 That is still true, and I would like to share some pictures to illustrate my transition.
00:00:36.540 This is where I used to live in Toronto, with a big 'sold' sign in front of my house.
00:00:42.480 If anyone has ever moved houses, you know it can get a bit chaotic, especially if there’s not much to take.
00:00:48.300 Here's my dog, looking really confused amongst all the boxes.
00:00:55.620 We had to pack everything, including our kits in boxes. My wife is pretty happy now.
00:01:02.520 Matthew is doing okay too. It was definitely a stressful time.
00:01:08.340 Now we live in Seattle, which is much prettier than where we lived in Oakville.
00:01:14.040 Seattle has a beautiful landscape with trees and mountains, unlike the flat, suburban feel of Oakville.
00:01:19.320 This is where I work now, at Building 43, with Mount Rainier in the backdrop.
00:01:25.560 This picture was taken on one of those rare snowy days in Seattle, which happened to coincide with my arrival.
00:01:31.020 Just to set the stage, the thing I built before coming to Microsoft was the Ruby CLR bridge.
00:01:36.720 Many of the topics I will discuss today relate to the problems this bridge aimed to solve.
00:01:41.880 The challenge is how to enable a dynamic language like Ruby to interoperate with static libraries.
00:01:47.159 This raises an important question: why would anyone want to run Ruby on another virtual machine, be it JVM or CLR?
00:01:53.759 The fundamental reason is to gain access to the libraries that exist on that platform.
00:02:00.119 However, this is quite a complex problem with no straightforward solution.
00:02:05.939 If you're writing Python, for instance, and want to access static libraries, the process will fundamentally differ from how Ruby would handle it.
00:02:13.319 Although there are common elements, the interoperability layer will require tailored solutions.
00:02:19.800 It's important to ensure that writing a Ruby program that communicates with CLR libraries feels natural.
00:02:26.099 We want it to feel like you're writing Ruby, not C# with a Ruby syntax.
00:02:32.640 Throughout this talk, I will share insights that reflect my thoughts on this matter.
00:02:39.840 At various points, I will compare decisions made by the IronPython team.
00:02:47.220 The cultures of the Ruby and Python communities differ significantly.
00:02:52.500 The Ruby community can be quite dogmatic about specifics such as method naming.
00:02:58.620 In contrast, the Python community tends to be more flexible.
00:03:04.440 I'll highlight how these cultural differences have led to various design decisions.
00:03:09.720 Now, I'd like to show this slide, which I love: Kathy Sierra's measure of success.
00:03:15.239 It represents two circles: what you want to do versus what you actually do.
00:03:20.400 The goal is to maximize the overlap between these two circles.
00:03:26.099 Often, they don't align, especially for those early in their Ruby careers.
00:03:32.640 I find that the hours we dedicate don't always lead to progress.
00:03:39.120 Coming to Microsoft was a strange experience for me.
00:03:44.880 I had never worked for a big company before, and I had typically avoided traditional full-time jobs.
00:03:50.520 Transitioning to Microsoft was quite the culture shock.
00:03:57.240 However, despite the overhead, I find that I have a lot of freedom.
00:04:02.040 The transition didn't feel as difficult as I anticipated.
00:04:07.920 Now, I want to talk about some of the more interesting technical aspects.
00:04:14.640 How many of you here are currently writing code on top of .NET?
00:04:20.760 Okay, about five of you. How about on the JVM?
00:04:26.580 Alright, some others.
00:04:32.400 I want to give the audience a quick overview of virtual machine environments.
00:04:40.140 A good way to understand the differences is by writing a simple application.
00:04:46.920 Let's start with a simple C# application.
00:04:53.640 Creating a Hello World app might seem tedious, but it's a good exercise.
00:04:58.920 So let’s write hello.cs.
00:05:05.760 Now we have hello.exe.
00:05:12.540 This program does what you would expect it to.
00:05:18.060 What becomes more interesting is when we consider a utility called Reflector.
00:05:25.200 Reflector is a program developed by Lutz Roeder, a colleague.
00:05:31.560 This program allows you to explore metadata and understand the inner workings of .NET.
00:05:39.960 Lutz Roeder is a fascinating individual who worked on Intentional Programming.
00:05:46.440 Intentional Programming was a significant research project at Microsoft.
00:05:54.960 It sought to revolutionize programming but only really left behind a remarkable editor.
00:06:02.520 Reflector was built by Lutz as a way to establish his identity at Microsoft.
00:06:11.640 He wanted to ensure everyone at Microsoft knew his name through this tool.
00:06:18.240 Now, let's look into how Reflector actually works.
00:06:24.480 When you explore the app we just wrote, you start to see the metadata it reflects over.
00:06:32.400 This tool essentially reverses any arbitrary chunk of Intermediate Language (IL).
00:06:39.720 With the help of Reflector, you can see the representation of your code.
00:06:46.800 It transforms what you've written back into readable code.
00:06:53.520 Reflector is a valuable tool for exploring the .NET platform.
00:07:00.360 Let's now take a look at a simple IronPython app.
00:07:06.120 I want to show you how IronPython translates to IL.
00:07:13.920 Let's see what happens when we compile a simple IronPython app.
00:07:22.200 I often forget the switches for compiling, so bear with me.
00:07:30.000 As it compiles, note how the size of hello.exe changes.
00:07:35.880 Now, let's examine the executed code in Reflector.
00:07:42.060 Navigating this can be tricky because of its size.
00:07:47.520 Inside it, you will notice many interesting components.
00:07:53.400 Let's disassemble the main method here.
00:07:59.880 You’ll see a lot more detail than you would with a plain method.
00:08:06.600 The goal of Reflector is to explore the dynamics of the code.
00:08:13.820 Reflector helps bridge the understanding between Ruby and .NET.
00:08:20.640 Now, let’s discuss the Dynamic methods in CLR.
00:08:26.520 Dynamic methods are lightweight and optimized for quick execution.
00:08:34.500 When you invoke a dynamic method, it first compiles into native assembly.
00:08:41.720 After the first invocation, it calls the previously compiled code.
00:08:47.160 Dynamic methods allow for just-in-time compilation tailored to runtime needs.
00:08:54.420 When they are no longer needed, the garbage collector can reclaim the memory automatically.
00:09:01.560 This feature is essential for dynamic language interoperability.
00:09:07.560 Dynamic methods handle memory management efficiently, preventing memory leaks.
00:09:13.440 Now, let's look at the various techniques for Ruby interoperability.
00:09:20.640 We are working primarily with the Ruby CLR implementation today.
00:09:27.180 Ruby's native implementation (CRuby) allows us to build C extension libraries.
00:09:33.420 Imagine creating a Ruby class that calls a C-based extension.
00:09:39.960 This impacts how we invoke methods between Ruby and CLR.
00:09:45.420 If I want to call a method in C on Foo, we need to bridge that gap.
00:09:52.320 With Ruby CLR, we create a proxy class that looks just like a C# class.
00:09:58.740 This way, method calls are correctly marshaled to the CLR side.
00:10:05.880 Dynamic methods now make this process seamless.
00:10:13.260 To illustrate, we can overload method signatures, even with different return types.
00:10:21.480 But Ruby doesn't allow function overloading based on return types.
00:10:27.780 At runtime, we have to determine which method to call based on the parameters supplied.
00:10:34.560 On the CLR side, we marshal the parameters as necessary.
00:10:40.560 The magic of dynamic methods makes this process easier.
00:10:46.920 In Ruby CLR, we use a combination of method_missing and const_missing to manage method calls.
00:10:54.600 This allows us to build the necessary proxies dynamically when functions are invoked.
00:11:02.760 As we dive deeper, let’s look at specific implementations.
00:11:09.780 For example, we can import the ArrayList type into Ruby seamlessly.
00:11:15.720 Once imported, we can call methods such as add seamlessly.
00:11:23.880 Ruby's syntax naturally integrates with .NET functionalities.
00:11:29.280 You can index into the ArrayList using Ruby’s syntax too.
00:11:35.880 Our events also map naturally into Ruby blocks.
00:11:43.320 When a button click event occurs, it invokes the corresponding Ruby block.
00:11:48.840 This example demonstrates the seamless interaction from CLR to Ruby.
00:11:57.720 The interfaces also present an interesting challenge.
00:12:05.040 We must expose .NET interfaces appropriately within the Ruby environment.
00:12:12.600 The .NET interface becomes a proxy within Ruby’s dynamic system.
00:12:17.520 This mirrors the C# syntax and provides a familiar experience.
00:12:25.740 Now, I want to clarify what this looks like for an ArrayList.
00:12:33.240 An instance of ArrayList will behave just like a Ruby object.
00:12:39.360 I can directly manipulate both from Ruby and CLR without issues.
00:12:45.420 However, challenges arise with the need for method overloading.
00:12:52.680 In scenarios where overloads exist, we must manage type resolution carefully.
00:12:59.520 Issues can occur where Ruby types don't match CLR types.
00:13:06.240 As programmers, we must address these discrepancies through shims.
00:13:12.240 The process helps distinguish between methods and ensures correct invocation.
00:13:19.200 The overall goal is for Ruby developers to feel at home while working with .NET.
00:13:26.040 The techniques implemented in Ruby CLR promote natural syntax and usability.
00:13:32.760 In scenarios involving generics, we need to ensure clarity for developers.
00:13:39.600 Generics can sometimes complicate method resolution.
00:13:46.680 However, we implement necessary limitations to keep operations straightforward.
00:13:52.920 When methods don’t have overloads, the calling becomes much more efficient.
00:14:00.240 This is a crucial aspect of how Ruby interacts with .NET libraries.
00:14:07.320 A notable design consideration is how we manage method overloading effectively.
00:14:14.040 We want to create methods that are intuitive for Ruby users.
00:14:21.840 There’s an interesting trade-off when developing features.
00:14:28.920 If overloads are ambiguous, developers might get lost in method resolution.
00:14:36.240 This confusion can hinder the user experience.
00:14:42.600 By providing clear interfaces, we reduce complexity.
00:14:49.800 Ultimately, the aim is to create seamless integration while using Ruby on .NET.
00:14:56.880 We uphold the principles of Ruby's dynamic nature throughout the interoperability.
00:15:04.920 In closing, I hope to encourage further exploration of Ruby CLR.
00:15:11.560 There's much more to discover, and I look forward to the advancements ahead.
00:15:18.480 Thank you for your attention. I'm happy to take any questions.
00:15:27.120 What if someone only has a PowerPC system?
00:15:35.760 You can still use Mono, but challenges exist.
00:15:41.400 The lack of a C++ compiler on Mono creates barriers.
00:15:48.600 Nonetheless, there are community efforts addressing this.
00:15:55.440 The contributions of IronPython provide some valuable insights.
00:16:01.800 There are ways to navigate the Mono challenges for Ruby CLR.
00:16:08.640 You might need to disassemble and recompile for compatibility.
00:16:14.520 Questions, feedback, or future suggestions are always welcome.
00:16:21.360 Thank you for engaging, and I appreciate your attention.