ActiveRecord and Windows Forms
This is a really exciting development in RubyCLR. I’ve taken the first steps in integrating Rails’ most excellent ActiveRecord object-relational mapping layer with Windows Forms data binding.
Here’s a screenshot of the result:

And here’s the code:
require 'winforms'
include ActiveRecord
Base.establish_connection(:adapter => 'sqlserver',
:host => '.\SQLEXPRESS',
:database => 'rubyclr_tests')
class Person < Base
end
class MainForm
def initialize
form = Form.new
form.Text = 'ActiveRecord and Windows Forms'
grid = DataGridView.new
grid.dock = DockStyle::Fill
grid.data_source = Person.find_all
form.controls.add(grid)
@form = form
end
end
WinFormsApp.run(MainForm)
There’s a lot of heavy lifting going on behind the scenes. The call to Person.find_all returns a Ruby Array object which I marshal to the CLR. However, my Ruby Array object isn’t any ordinary Ruby Array object. RubyCLR can implement CLR interfaces in Ruby, so my Array object also happens to implement IBindingList.
The Array contains Person objects, which all derive from ActiveRecord::Base. RubyCLR knows how to marshal ActiveRecord::Base objects so that I transparently create a CLR ‘anonymous’ type that exposes all of the Ruby ActiveRecord fields as CLR properties. I marshal by reference, so that changes in the ActiveRecord object will be propagated via IBindingList notifications to the DataGridView control.
This is an extremely important scenario to cover since a primary goal of RubyCLR is to enable the creation of rich client business applications. This is a major step towards enabling this scenario.
I just checked in the code for this feature into the rubyclr trunk. So you can play with it if you want. Keep in mind that this is all prototype code, but at least this sample works and all of the existing unit tests still pass (182 tests, 365 assertions).


03. May, 2006 







Now that is cool!
I wonder if you might be able to give me a tip on creating a DataTable from a Ruby Array though. It’s easy enough to create a row, fill it, and add it to the DataTable, but the performance on about 1.2 million calls (create_row, add 5 fields, add the row, so 7 calls and about 167,000 rows) is a little dissapointing.
I mean it’s great considering all the magic that’s going on, but it probably takes around 90 seconds, so that means I’m spending almost half my process time doing interop as far as I can tell. Do you think there might be a quicker way? Maybe an alternative to passing a DataTable to an SqlBulkCopy object?
Hmmm … the perf of the bridge should be much better than what you’re observing. That said, I haven’t really done much perf tuning recently.
Let me do some experiments tomorrow to see if I can pinpoint where the bottleneck is.
Whoa! This is great stuff. Providing the foundation for Ruby in the CLR can help adoption rate of dynamically types languages in the corporate world.
When will you be picked up by Microsoft like that IronPython guy?
You Rock!!!
This is just *amazing*
This is just *amazing*
Hi John,
This is really amazing stuff. I’ve recently fallen in love with Ruby, and am looking for a way to do Ruby client programming on Windows and Mac.
How’s the performance of RubyCLR code as opposed to C# code? Even if you just have a general sense, that would be useful. Is there a big difference is speed, or does it seem to be in the ballpark?
Also, I’d love to learn more about how RubyCLR works. Is there anything on the site you can point me toward? If not, no worries, I can go source code browsing.
Thanks for doing something so cool! I’m looking forward to trying this out on some future projects.
-Pete
Lead Software Engineer
NextEngine, Inc.
http://www.nextengine.com
Pete – Ruby is quite a bit slower than C# code. It’s within an order of magnitude when doing equivalent things. That said, however, Ruby really isn’t all that suitable for high-performance computing – that’s not really it’s forte. However, you could do some interesting metaprogramming that results in *generating* really high performance code. I fully support inlining CIL, C#, VB.NET and even JScript.NET code.
I like to think of C# as the “Ruby assembly language”
As for implementation details – just read different entries on this blog – I’ve been at this for a while … I really need to write an ‘overview’ article on how it really works, but bottom line is that the marshaling shims that I use to interop with the CLR are all generated on the fly as CLR DynamicMethods. So the interop layer is always compiled x86 code at runtime.
If you want to learn about Ruby metaprogramming, check out the source code for RubyCLR itself. Most of the interesting parts are written in Ruby- the C++ is really there to interop with the bare metal of the CLR.
This is some really cool stuff
Also since your using a bridge the processing of the ruby language parts are still done by the Ruby interpreter right ?
Would it also be possible to use Og ?
Or is that just a matter of testing it out myself ?
It’s something that you should definitely try out. I haven’t put any effort into name collisions etc. with respect to multiple metaprogramming libraries interacting with each other. I have ideas about how to make this more robust, but haven’t had the cycles to really try them out yet. That said, bug reports in this area are always welcome
John Lam wrote: “That said, however, Ruby really isn’t all that suitable for high-performance computing – that’s not really it’s forte.”
I disagree. In high performance computing no matter what language you’re using – even the best of them – (C, C++, Fortran, even ASM) – and certainly for the weaker ones (Java, etc) – you’ll be spending 80%+ of your CPU time in high-performance vector or matrix libraries. Whether the relatively small amounts of glue logic to string those together is in Ruby or C doesn’t really matter at that point. Ruby has a good and growing numerical library (NArray) that makes it competitive with anything else that uses similar libraries. Eventually you’ll want these matrix libraries to use hand-tuned algorithms that make use of the parallelization specific to your CPUs (i.e. the multiple integer and floating point units and SIMD features of most modern chips – and featuers like OpenMP that’ll distribute a single loop over multiple CPUs) – but I’m guessing that these’ll be callable from the CLR or built into it where any language including RubyCLR.
I think Ara Howard(?)’s examples on the ruby boards are good examples of this where his extentions to NArray are used to do pretty impressive high-performance computing tasks.
Re-reading what you wrote, I guess I agree with you that Ruby is not what anyone will ever write the high-performance computing libraries in (but neither is C# until someone writes a loop-parallizing-C# compiler like they have for fortran) – but I don’t think that means it’s inappropriate for high-performance computing — just that you need to use the right libraries.
I guess I didn’t really define ‘high performance computing’ very well. It’s not just numerical tasks, it can be things like parsing a very large file efficiently. Having a language where I can absolutely control how memory is laid out to avoid unnecessary copying is critical to making that stuff run fast. We’re not going to be writing that code in Ruby or C# – well *maybe* C#, but I’d definitely prefer C++/CLI for that kind of work.
I am interested if you are going to make it open-source, because I only see a dll for the ruby interpreter
sorry, please delete the last comment. there is a source code written in C++.