In the last couple of years we witnessed a sharp rise of the popularity of both Ruby and its most famous project Ruby on Rails (RoR from now on). Developers flocked to “the other side” from many different languages and platforms: PHP, Java, C#… The most famous public switch in the .NET world was Mike Gunderloy’s – he had a great consulting job as a .NET consultant and a large following reading his “Daily Grind” (no link since the grind is now discontinued), but has now moved on to RoR exclusively.

Most of the other platforms have since adopted some of the features of the RoR. On the frameworks side we have Python with Django, Java with Grails (yes I know it’s actually based on Groovy), PHP with CakePHP and .NET with MonoRail. On the fundamentals side we have JRuby that allows Ruby and thus RoR to run on the JVM and the .NET will soon have IronRuby that should do the same for the CLR (or DLR to be more precise).

It would be naive to think that Microsoft’s developer division did not plan to launch a .NET based framework similar to RoR. Despite the success of the ASP.NET, as it is now ASP.NET is a lot more friendly to beginners and those demoing the technology. Experienced developers require more structure to the code (MVC pattern is one way to introduce structure), unit testing, less hand-holding and more control over the generated HTML.

Why didn’t Microsoft announce ASP.NET MVC (I hope the name will change) sooner?

My guess is that both the underlying platform (CLR) and the languages on top of it (most notably C# which is a “primary” language for the platform) could not compete with RoR/Ruby in coolness, brevity and elegance. But with the C# 3.0 and LINQ, we’re finally there.

Let’s look at the list of some of the things Ruby/RoR had that C#/ASP.NET didn’t have prior to the .NET Framework 3.5 and then dissect them all one by one:

  1. ActiveRecord
  2. blocks/lambdas
  3. easy way to extend any class with a new method
  4. hashtables everywhere, including simulated named arguments
  5. easy getters/setters and anonymous types

1. ActiveRecord is the trickiest to get right. As much as I hate to delve again into the religious debate about the need for ORM tools, I have to mention that lightweight ORMs can be useful. ActiveRecord and LINQ are both such ORMs. They don’t try to be everything to everyone nor to resolve every Object Oriented/Relational mismatch there is. LINQ is a very good substitute for ActiveRecord. One feature of RoR is missing though and that is declarative database modeling and migrations. No database schema rests the same from the initial design and the decision to include the process of schema upgrades directly in the development process is a great decision for RoR.

2. Blocks in Ruby are undoubtedly cool and used all over the place. .NET has very similar concepts, even keywords overlap, but the meaning is not the same. Keyword yield in Ruby is different than yield return in C#, yet both are used in extremely similar contexts. Let’s look at Ruby example:

def useless
  puts 'Starting useless method.'
  yield
  puts 'Ending useless method'
end

useless { puts 'Outside useless' }
# prints "Outside useless" in-between "Starting..." and "Ending..."
a = [1, 2, 3]
a.collect { |elem| 2 * a}
# gives [2, 3, 6]

collect is method that will apply user-supplied block (read: anonymous method) to each element of an array and return a new array with the results. It does so by yielding every element of the array to your block, then appends the result into an array that it returns. So it looks like yield is great for iteration like scenarios – it is. But look at the first example (contrived, yes). Method prints some text, yields control (not giving any value and ignoring the return value) to your block, then prints more text.

The thing is, blocks are just anonymous methods. The nice thing with blocks in Ruby is that you don’t have to pass them to methods, yet any method is capable of receiving them. It’s as if any method in the C# would accept one extra invisible parameter, an anonymous method, with any number of parameters and any return value. Let’s rewrite the useless method in C# 3.0:

public class MustHaveClass {
  public static void Useless(Action block) {
    Console.WriteLine("Starting useless method");
    block();
    Console.WriteLine("Ending useless method");
  }
}

// call it with 
MustHaveClass.Useless( ()=> { Console.WriteLine("Outside useless"); });

It's more wordy, but the point is the same. Action is just a delegate with no parameters and no return value. We have to spell this out – both the number and type of parameters as well as type of the return value. If you expect a different kind of “block”, you’ll have to change the signature to the more appropriate delegate (look up Func in the Reflector). So the keyword yield in Ruby is actually equivalent to the delegate invocation in C#. Also note that I’m using lambda syntax for anonymous method here (new with the C# 3.0). I could have also used “old” style anonymous delegate from C# 2.0, but lambdas are more readable for larger number of parameters so I always use them by reflex.

Unlike Ruby, C# does not use blocks/anonymous methods for iteration. To make things more confusing for comparison, simplified iteration is achieved via yield return keyword. In any case, sending blocks to methods and using them is now really easy with the lambdas in C# and is not very ugly nor there is too much to type.

3. Easy way to extend classes has always been one of the primary features of Ruby. C# 3.0 gives you extension methods and though they are not as powerful as in Ruby, the essence is there. I already wrote about how to implement Rails-like extension methods and I wrote about surprising behavior you can achieve with the extension methods. Thus I won’t go into detail any more.

4. Hashtables are everywhere in Ruby and in RoR. They are particularly useful for dynamic parameter passing. Up until C# 3.0, there was no easy way to create a hashtable (or dictionary for strongly typed situations), but no more. Here’s how to create dictionary on the fly:

 new Dictionary<string, int>() { { "one", 1}, { "two", 2 } };

A bit wordy at the beginning, but simple enough for the body of the initializer. There is a syntactically simpler alternative (at the cost of using reflection) demonstrated in the next point.

5. Anonymous types and trivial getters/setters enable many scenarios that used to be either too “wordy” or just impossible. The reason LINQ’s syntax is so simple has in part to do with anonymous types. Example:

from c in Customers
where c.Name == "SomeName"
select new { FullName = c.FirstName + c.LastName };

Instead of returning back a type of Customer I am returning unnamed type because I'm only interested in its property called FullName. The scenario is partially enabled by a trivial way to get a property with no code for getters/setters.

Ruby has attr_accessor decorator method that generates getter and setter methods. C# 3.0 allows you to just say get; set; in the declaration of a class and you’re done.

Instead of dictionary as a primary means for dynamic parameter passing, you could also use anonymous types. Keep in mind that on the receiving side, you’ll have to use reflection to figure out what you received (but it’s not hard). Example from above would look like this:

new { One = 1, Two = 2} 

A lot simpler, no?

 

Let’s not get carried away here: language features are cool, but ultimately it matters more if the framework is well written or not. Based on what I’ve seen, ASP.NET MVC is well designed – we’ll talk about how well written it is once at least beta code becomes available. It looks like most of the good things from RoR have been faithfully duplicated so I have high hopes

In a blog post I wrote a few months ago I thanked Microsoft for giving us free Express versions of the Visual Studio. A reader rightfully complained that I should probably thank the Open Source community first – without the pressure from Eclipse and other IDEs, it’s questionable whether Microsoft would ever consider giving away Visual Studio Express.

Along same lines then – thanks to the Ruby community and thanks to David who started the Ruby on Rails. Thanks to you the .NET developers will get a cool MVC Web framework.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
0 Comments