Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

IronRuby and the Reactive Extensions for .NET Together at Last

Recently, there was a release of IronRuby 1.1, which had a number of new features including targeting .NET 4 only, as well as the most interesting part, the support for Extension Methods.  Taking a cue from the examples, we can write a simple LINQ comprehension using extension methods defined in the System.Core library’s System.Linq namespace.  To make this happen, we need to load our assembly System.Core and then use the extension methods defined in the System.Linq namespace.

load_assembly 'System.Core'
using_clr_extensions System::Linq

We’ll also need a way to go from the Ruby Enumerable to .NET IEnumerable<T> instances.  To bridge that, we’ll extend the Object class and define a to_seq method, which takes a type, should we need to make our IEnumerable<T> instance anything other than a Object.  We then create the IEnumerable<T> instance by calling to_a or to array on the Enumerable itself.

class Object  
    def to_seq(type = Object)    
        System::Linq::Enumerable.method(:of_type).of(type).call(self.to_a)  
    end
end

Putting this all together, I take a Ruby enumerable and convert to a .NET IEnumerable<T> instance, square the numbers and get those which are divisible by 3 and then print the results.

load_assembly 'System.Core'
using_clr_extensions System::Linq

class Object  
    def to_seq(type = Object)    
        System::Linq::Enumerable.method(:of_type).of(type).call(self.to_a)  
    end
end

(1..10).to_seq.
    select(lambda { |x| x * x }).
    where(lambda { |x| x % 3 == 0 }).
    each { |x| puts x }

This works great as it prints out the numbers 9, 36 and 81.  This is a great interop story although I’m sure if I’m using Ruby, I might just stick with the Enumerable module.  But then I looked at the Observable Module in Ruby and I wasn’t really happy with what I saw there in terms of adding/deleting observers as well as the notification is pretty much a straight copy of the Gang of Four pattern, which I think we’ve moved past. 

This got me thinking, that if we can go back and forth with Ruby’s Enumerable module to the .NET IEnumerable<T> interface, then we should be able to do the same with the Reactive Extensions for .NET and the IObservable<T> interface.  We’ll recreate the example above, but instead of the push model of Enumerable, we’ll be pushing objects to it instead.

Let’s first load our assemblies that we’ll need and include the proper namespaces and extension method namespaces.  We’re including the System namespace as that contains the overloads for the Observable.Subscribe method to take lambdas instead of an IObserver<T> instance.

load_assembly 'System.Core'
load_assembly 'System.CoreEx'
load_assembly 'System.Reactive'

include System
include System::Linq

using_clr_extensions System
using_clr_extensions System::Linq

Once we’ve done that, let’s take the knowledge about taking an Enumerable and turning it into an IEnumerable<T> by taking that same Enumerable and turn it into the IObservable<T> via the to_observable (ToObservable) method.

class Object  
    def to_seq(type = Object)    
        System::Linq::Enumerable.method(:of_type).of(type).call(self.to_a)  
    end
    
    def to_observable(type = Object)
        System::Linq::Observable.method(:to_observable).of(type).call(self.to_a)
    end
end

Now we can focus on the problem at hand which is to create our IObservable<T> instance.  As above, we can take an Enumerable range of 1 to 10 and turn that into an observerable.  Once we do that, we can now call our select and where methods appropriately which creates our observable sequence.

observable = (1..10).to_observable.
    select(lambda { |x| x * x }).
    where(lambda { |x| x % 3 == 0 })

We now have our observable sequence, but now what?  Well, since we’ve imported the extension methods from the System namespace, we’re able to use the Subscribe overloads that take lambdas which cover the OnNext, OnError and OnCompleted cases.  In this case, I’ll handle all three, but in this instance I only really need to handle just the OnNext.  I’ll use the do syntax instead of the lambda just to show you that both work.

observable.subscribe(
    lambda do |next_value|
        puts next_value
    end,
    lambda do |error|
        puts '#{error.message}'
    end,
    lambda do 
        puts 'done!'
    end)

Having this code in place, I can run this and sure enough I have printed to my screen:

9
36
81
done!

Interesting possibilities here, including comparing and contrasting the Ruby Observable and the IObservable<T>.  More to come in the next post!

Conclusion

With the Reactive Extensions for .NET, we have a nice cross-language support for building a bridge to asynchronous and event-based programming.  Coming with the latest release of IronRuby, we now have the ability, and a rather nice one at that, to consume extension methods that are predefined in other languages, which opens a whole new set of opportunities for interoperability.  In the coming posts, I’ll take a look at what else I can do in this space to see that we can fact help solve some of the hardest problems around asynchronous and event-based programming.

So with that, download it, and give the team feedback!

This entry was posted in Event-based Porgramming, Reactive Framework, Ruby. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Charles,

    Yeah, it wasn’t pretty solution earlier, and now it’s a much cleaner process.

    Matt

  • http://charles.c.strahan@gmail.com Charles Strahan

    Very neat, Matt. I”ll have to play with the Parallel Extensions from IronRuby some time, too.

    The new support for extension methods is pretty sweet. It would have made my code a lot simpler back in the day, when I wrote an example of using DynamicQueryable from IronRuby:

    http://charlesstrahan.com/blog/2010/03/27/linq-in-ironruby/

    -Charles

  • http://wizardsofsmart.net/ Ryan Riley

    Very cool. I’m curious to see your attempt at making callcc in IronRuby via Observable.Create. :)

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Jimmy,

    You’re welcome! A few more posts to do here before I’m done for now.

    Matt

  • http://jimmy.schementi.com Jimmy Schementi

    Thanks for doing this write up =)