« Company Meeting Day | Main | We need more help and we're willing to pay for it! »

September 10, 2007

IronRuby Libraries

The IronRuby libraries are divided into two groups: built-ins and the standard libraries. We will distribute both sets of libraries in the standard IronRuby distribution. The distinction is whether a library must be required prior to use.

The code is organized in two separate directories under trunk\src:

src

The built-in libraries are compiled alongside the rest of the compiler into the Ruby.dll assembly (this will be renamed in the future to IronRuby.dll). The standard libraries are compiled into IronRuby.Libraries.dll for the time being. These libraries may be refactored into some additional assemblies in the future, but for the time being we'll likely go down the path of extending the assembly-level RubyLibraryAttribute to identify the Ruby libraries implemented within an assembly. All Ruby libraries must contain this attribute. Kernel#require will inspect these attributes when it goes to try and find a library by name.

Let's walk through some simple library code to better understand what's going on:

Ruby - Microsoft Visual Studio

This defines a module called Sample which will be loaded implicitly when we require the IronRuby.Libraries assembly. In the future, we will be able to require Sample directly. We can run this code via rbx.exe:

Administrator Visual Studio 2005 Command Prompt - rbx (2)

There's something interesting in the implementation of the Hello method. As you know, all Ruby methods must return a value, yet we've defined Hello as a method that returns void. If you look at the output of the console, you'll see that it returns nil, as expected. So how did this magic work?

Let's take a tour via the debugger. Much of the magic happens in RubyActionBinder.cs. Set a breakpoint on MakeRuleForInvokeMember<T> and execute the require from the screenshot above (you'll need to step over the execution of the require method itself). When you execute Sample.hello, you'll hit the breakpoint.

First, notice that the type of T is DynamicSiteTarget<object, object>. This method is responsible for generating a rule from the available information: the name of the method, the type of the receiver, the execution context, and some information about the parameters.

What's a rule? A rule is (currently) a conditional statement. There are two parts, a Test and a Target. The Test guards the Target, and if true will execute the Target. Rules are used by the DLR to generate Dynamic Sites, which is our mechanism for caching the results of our method lookups.

Here's some pseudo-code for the rule produced by MakeRuleForInvokeMember<T>:

if (typeof(target) == Sample && !HasVersionChanged(target))

  return target.hello();

Rules contain DLR expression trees. These expression trees are converted into executable CIL by the DLR. This is what the generated IL looks like after decompiling back to C# using Reflector:

public static object Handle2(object[] objArray1,

  FastDynamicSite<object, object> site1, object obj1)

{

  if ((obj1 == ((RubyModule) objArray1[0]))

     && (((RubyModule) objArray1[1]).Version == 0x815))

  {

    Sample.Hello((RubyModule) obj1);

    return null;

  }

  return site1.UpdateBindingAndInvoke(obj1);

}

Notice that we return null from the site since the method binder knows that we are invoking a void method, so we generate the correct return statement.

If you want to see the dynamic site yourself, you can run IronRuby in debug mode using these command line switches:

rbx.exe -X:SaveAssemblies -X:StaticMethods -D app.rb

app.rb is a file that contains the code that we're running. IronRuby will generate a file called snippets1.dll in the same directory as app.rb. Open it up using Reflector, and you'll see the dynamic site that we generate for calling Sample#hello:

Lutz Roeders .NET Reflector

Lutz Roeders .NET Reflector (3)

Quite a lot of the code in the RubyActionBinder is targeted for refactoring, so this isn't what it's going to look like in the long run. However, it's a good start and it generates correct, fast code today.

In a future post, I'll walk you through more complex samples where we accept parameters, dispatch to blocks, throw exceptions etc. Hope this helps you understand some of what we're doing for method dispatch to C# library code today.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/2419952/21497135

Listed below are links to weblogs that reference IronRuby Libraries:

Comments

I have a question for you...where can I find the settings in order to make my VS to look like screenshot 2 :) ... nice article though

@Kiril: here's the link: http://www.iunknown.com/2007/06/vibrant_ink_vis.html

Beware that if all you want is the coloring that you'll need to check the appropriate options in VS when importing my settings file.

This is probably a stupid question, but how do you force VS to not place the "{" on a new line? It looks like the IronRuby and IronPython format the code with the "{" at the end of the previous line, but VS keeps moving it to a new line for me.

@Mike:

In Tools/Options/Text Editor/C#/Formatting/New Lines

uncheck place open brace on new line for ... check boxes.

See? I told you it was a stupid question. If only I could set that on a project by project basis...

Nice one. Thanks, John.

Have a great special day.

silly question but is the DLR & IronRuby tied to silverlight? will IronRuby work with all aspects of .net?

@Chris: Nope DLR + Ruby is not tied at all to Silverlight. It will run anywhere the CLR (and CLI compliant runtimes like Mono) can run.

I tried following the screencast so I can check out IronRuby, but when I try to build it in console with rake compile, I get "Could not find RubyGem pathname2 (>= 0.0.0)"
when I try to do it in VS I click on "Rebuild Solution" and nothing happens. It literally just sits there like I never clicked anything. Any ideas?


~Jeremy

@Jeremy:

If you update from svn, you should get the new Rakefile that will automatically install the pathname2 gem. If that doesn't work you can manually install via "gem install pathname2"

Regarding VS, you'll need to change the build configuration to Debug. I removed ExternalDebug and ExternalRelease from the latest source drops and you likely have an older .suo lying around that defaults to ExternalDebug.

could you increase the padding to code a bit so that it is farther away from border?

Hi John,

Just curious to know about the code conversion.

Currently we have few tools that converts the Vb.Net codes to C# and Vice Versa.

In future will it be possible to convert the IronRuby Codes to C# and Vice Versa...?

Just Curious thats all.

@SoftMind:

You can do this sort-of today by decompiling IronRuby to C# via Reflector. However, the generated code is not pretty at all and does not reflect the way you would want to code the same algorithm in C#.

John, I installed ruby186-26_rc2. After "gem install pathname2" which installs pathname2 (1.5.2) I get the following error when I try to "rake compile": "c:/ruby/lib/ruby/gems/1.8/gems/pathname2-1.5.2/lib/pathname2.rb:487: [BUG] Segmentation fault ruby 1.8.6 (2007-09-24) [i386-mswin32]". Maybe it would work with a different version of pathname2. Any ideas?

I did

> gem install --remote pathname2

and used my VS.Net SDK command window (to fix some path errors)

and everything compiled fine.

Using Ruby 1.8.5 on Windows XP

@TalbottC:

There seems to be a problem with the latest builds of Ruby 1.8.6. I downgraded to a pre-rc build and pathname2 works just fine.

Thanks John. That did the trick. I downgraded to 1.8.6-25 and it works great. BTW: great talk at P&P Summit in Redmond last week.

Hi John,
I'm crafting a StringIO class for IR and hope to send for consideration soon (as a base for the yaml).

I'm quite new on this and don't know which namespace it should belong. Currently I have it on Ruby.Builtins but should it go on Libraries?

Sorry, I meant that they should go on Ruby.Extensions

Is the pathname2 still an issue or is it been resolved? I checkout the code last week and getting the same error. May be I am missing something?
Thanks.

@Nair: gem install pathname2

Post a comment

If you have a TypeKey or TypePad account, please Sign In

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