« December 2005 | Main | February 2006 »

January 2006

January 18, 2006

Windows Forms and Value Types

Justin in my comments reported not being able to create a simple MessageBox.Show('Hello, World') app. There were two things missing in Justin’s app: explicitly loading the System.Windows.Forms assembly, along with a bit of confusion about Ruby namespaces and scoping.

Here’s a version of Justin’s code that should work:


require 'rubyclr'
include RubyClr

RubyClr::reference 'System.Windows.Forms'

include System
include System::Windows::Forms

MessageBox.Show('Hello, World')

It displays the message box and then promptly crashes. Why? Because MessageBox.Show returns a DialogResult, which is a user-defined value type. I’m not marshaling user-defined value types yet, but it’s a very high priority for the next release of the bridge.

In other news, I’ve done some pretty major refactoring of the C++ code in my current internal builds – I was very unhappy with some of the code that I had in my first drop (hint: grep for ‘enema’ in the source). I’ve also got support for virtual call optimization in the current internal build.

I’m pretty busy writing ObjectSharp’s ASP.NET 2.0 Best Practices course the next couple of weeks, so I’m anticipating a new release of the bridge towards the end of next week. At the very least expect to see user defined value type marshaling working by then.

TimeSnapper and Personal Life Recorders

This year is the 3rd year that I’m a judge for the Jolt Software Awards. A couple of nights ago, I thought that I had submitted my votes for the first round of voting to select the finalists. As it turns out, somewhere along the way my votes got lost (I blame my general sleep-deprived stupor these days).

Fortunately for me, I was running TimeSnapper at the time. This incredibly useful utility takes a snapshot of your desktop every 5 seconds and records the result as a PNG image. So it was a simple matter to replay my day around the time I was entering my votes to see exactly what I voted for.

This morning I was chatting with my mother in law during our morning baby / toddler shift and I told her the story of Vannevar Bush’s description of a Memex which was his vision of a life recorder. A modern implementation of Vannevar Bush’s ideas is Gordon Bell’s MyLifeBits project.

A fairly full day’s worth of work for me is about 350MB worth of screenshots. That means that it would take about 100GB to store a year’s worth of screenshots, which translates into about $40 Canadian dollars today. Now until this data is searchable, I doubt that it will be tremendously useful, but I find it fascinating that it costs so little to digitize an entire year’s worth of my computer activity.

If you could synchronize those screenshots with a keystroke logger and a network activity monitor, you could quickly make a quick-and-dirty searchable archive. Hmmmm ….

January 12, 2006

First drop of RubyCLR

Here’s the first drop of RubyCLR.

I think this version is usable for folks who are interested in playing around with the current state of the bits. It supports constructor and method overloading, static and instance methods, properties, indexers, static and instance fields, events, multi-dimensional arrays, primitive (ints, floats, bools) value-type marshaling, and reference-type marshaling. Look at the tests2.rb unit test file to see the evidence.

Notable are the things that this release does not support. There is no support for generics, nor is there support for marshaling user-defined value types like Point.

There’s a rakefile in this project too if you want to compile the bits. I’ve included a compiled DLL for folks who don’t have MS C++ 14.0 installed on their computer.

This release requires the RTM version of .NET 2.0.

I haven’t tried to build anything using these bits yet outside of the unit tests, but I wanted to provide a drop for the curious.

I’m really interested in getting feedback about the implementation of the bridge. If folks have the time and could do a code review of either the C++ or Ruby code (or both!) I would greatly appreciate it.

Bug reports in the form of a unit test that can repro the bug would also be greatly appreciated.

The state of error messages in this release is more-or-less non-existent. I plan on fixing this once I tackle the next two hard problems: marshaling user defined value types and handling generics.

Events and RubyCLR

I got events up and running last night. It was a bit harder than I anticipated, and there’s still a bit of work that needs to be done around marshaling, but this unit test now passes:


public ref class CallbackTests {
public:
  event EventHandler^ Event;

  void CallMeBack() {
    Event(nullptr, EventArgs::Empty);
  }
};

class EventTests < Test::Unit::TestCase
  def test_simple_event
    c = System::CallbackTests.new
    c.Event do |sender, args|
      assert_equal 1, 1
    end
    c.CallMeBack
  end
end

January 11, 2006

RubyCLR update

I’ve been spending a surprising amount of time working on my Ruby CLR bridge. Ben sleeps on/around me for about 3 hours in the evening to give Carolyn 3 hours of uninterrupted sleep, and I’ve been using that time very productively to add features.

The older version of the bridge that I had working was a grotesque hack – it was essentially a bunch of experiments cobbled together in a Frankenstein-esque contraption. Anyone who has a copy of that code is respectfully asked to destroy it once I ship any of these newer bits.

One of the big things that I’ve been working on is getting a seamless array experience. I marshal data types between the CLR and Ruby by value where possible, and by reference in all other cases. So value types like floating point numbers and integers are marshaled by value (aka copied and converted) across the runtime boundaries. So code like this just works:


static array<int>^ StaticGetOneDimensionalArray() {
  return gcnew array<int> { 0, 1, 2, 3 };
}

a = MarshalerTests.StaticGetOneDimensionalArray
assert_equal 0, a[0]
assert_equal 4, a.Length

As you can see, I marshal by reference the array from the C++ function. But all of the elements of the array are marshaled by value, which lets me treat them as if they were native Ruby numbers.

I’ve also done a ton of performance work in this release. If you’re calling a method that has overloads, I take a slower path where I have to lookup at runtime the correct method based on the parameters that you’re passing. However, if the method doesn’t have any overloads, I generate a different shim that doesn’t do any runtime lookups – it just pushes parameters onto the call stack and invokes the method. The array code that you see above calls Array.Get which is not overloaded (unlike Array.GetValue which is) which results in extremely fast CLR array element access from Ruby.

I’m punting on some hard problems like generics for the time being. I have to add support for events before I ship this release; if Ben cooperates that should be by the end of this week.

Hanselminutes

Scott Hanselman is podcasting. I’m a huge fan of his recommendations on almost anything. I discovered Timesnapper by listening to his podcast today during lunch.

A nice Ruby moment today

I used to have a chunk of code that looked like:


def new_clrobj(ctor_info, sig = null)
  sig = ctor_info.signature if sig == null
  newobj   "#{ctor_info.clr_type}(" + sig.join(',') + ')'
end

It now looks like:


def new_clrobj(ctor_info, sig = ctor_info.signature)
  newobj   "#{ctor_info.clr_type}(" + sig.join(',') + ')'
end

It was one of those “it just works” moments that makes me love this language.

January 09, 2006

Our other boy

It’s been a long time since I’ve posted about Matthew:

He’s almost 28 months old now, and he’s starting his new pre-school on Wednesday. He’s a pretty bright boy; he can read fairly elementary books completely on his own, and his vocabulary is growing by leaps and bounds. He was impressing his new pre-school teachers today by doing a “reverse” flash-card trick – that is predicting the letter on the other side (these were the simple alphabet flashcards that have a picture on one side and a single letter on the other side) based on the picture. I guess all of Daddy’s hard work creating his birthday present paid off! :)

We got Matthew his first computer for Christmas this year. Well, it was really just one of Daddy’s older computers brought back to life with a PCI 802.11g wireless card. I was amazed by how quickly he learned how to use the mouse – it took maybe 2 days before he had it figured out. The hard part of course, is the fixed length of the cord, so you have to pick up the mouse or move it faster to get to where you want to go. We’re not using a wireless mouse so that the mouse doesn’t wander away.

He figured out the Start button pretty quickly, so I had to lock down the options there (although he is running under a normal user account – no admin privileges quite yet :). He also figured out how to start Explorer without any options present under the Start menu, and today he demonstrated his virtuosity with drop-down combo boxes – I caught him browsing the DVD drive today.

We’re working on typing skills next – Textpad appears to be his editor of choice right now. I think it will take some time before his hands get big enough to start using emacs :)

January 04, 2006

Ruby in the real world

Sam Gentile was wondering about where Ruby is used in the ‘real world’, and where I’ve personally used Ruby.

Sam, you can easily Google around to see where Ruby is being used in the real world. Check out the Rails web site for some pointers to some large web sites that are running on Rails.

As for where I’ve personally used Ruby and Rails, we wrote a lot of Ruby code for my last customer. The product hasn’t been announced yet, so I still can’t talk about it, but suffice to say that it’s a high performance e-commerce web service with two very large customers running on top of it (and many more to come).

We used Ruby to automate deploying the web service to our cluster. Ruby’s integration with COM made writing the ADSI + WMI goo much more pleasant. I even toyed with rewriting the core web service (which is a .NET web service) in Ruby and was able to exploit an optimization that simply was not possible using .NET and SQL Server. There was an intermediate result set that could easily be cached in-memory using Ruby that wuold net us at least a 10X performance increase over the existing .NET application.

To be fair, I could have done the same optimization using C#, but there would be no way that I could squeeze it down into 200 lines of very concise Ruby code. The other qualitative difference is that the caching optimization was just really obvious in the Ruby code; there was just so few lines of code to look at.

We also built out a Rails web site to support the API. Developers using the web service could run live queries against our catalog using the site. The web site would also generate the application code for them in their programming language of choice: C#, VB.NET, Java or raw SOAP calls. It’s very similar in spirit to the AWS Zone site (even though I’m convinced that we have a much simpler query API than Amazon does).

I’m convinced that Ruby and meta-programming is a great way to approach modeling business applications. That’s why I’m investing so much time building my Ruby to CLR bridge.

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