Sasha Sydoruk

Building a better mousetrap with XHTML, AJAX and RSS

C# vs Ruby Smackdown!

Finally I get to write a “smackdown” post. I had this post written for a while now, but just never got to publish it.

Here is my completely non-scientific comparison of C# and Ruby. I will come up with a simple task and will attempt to implement it in both languages. The results will be shown, but no analysis will be available; I don’t want to pick sides because I really like both languages and want to stay on good terms with both of them.

Enough of disclaimers, here is the task. Create a Day class and populate a collection of instances of class Day to represent a week. Display the week in the original order, reverse the order of the days, display the new order, restore the original order, show only the work day and show only the weekends.

Here is the expected output:

Regular Order
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday

Reversed Order
Sunday, Saturday, Friday, Thursday, Wednesday, Tuesday, Monday

Regular Order
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday

Work Week
Monday, Tuesday, Wednesday, Thursday, Friday

Weekend
Saturday, Sunday

Here is how I did it in C#:

   1:  using System;
   2:  using System.Collections;
   3:  using System.Collections.Generic;
   4:  
   5:  namespace RubyCsExample
   6:  {
   7:      internal class Example
   8:      {
   9:          public static void Main()
  10:          {
  11:              List<Day> daysOfWeek = Day.CreateWeek();
  12:              DisplayDays(daysOfWeek, “Regular Order”);
  13:  
  14:              //Reverse the order of the days
  15:              daysOfWeek.Sort(delegate(Day one, Day two)
  16:                                  {
  17:                                      return
  18:                                          (Comparer.Default.Compare(one.Ordinal,
  19:                                                                    two.Ordinal)*-1);
  20:                                  });
  21:              DisplayDays(daysOfWeek, “Reversed Order”);
  22:  
  23:              //Restore the order
  24:              daysOfWeek.Sort();
  25:              DisplayDays(daysOfWeek, “Regular Order”);
  26:  
  27:              //Show work week
  28:              DisplayDays(daysOfWeek.FindAll(delegate(Day d)
  29:                                                 {
  30:                                                     return !d.IsWeekend;
  31:                                                 }), “Work Week”);
  32:  
  33:              //Show weekends
  34:              DisplayDays(daysOfWeek.FindAll(delegate(Day d)
  35:                                                 {
  36:                                                     return d.IsWeekend;
  37:                                                 }), “Weekend”);
  38:  
  39:  
  40:              Console.ReadKey();
  41:          }
  42:  
  43:          public static void DisplayDays(List<Day> days, string message)
  44:          {
  45:              if (!string.IsNullOrEmpty(message))
  46:              {
  47:                  Console.WriteLine(message);
  48:              }
  49:              List<string> names = days.ConvertAll(new Converter<Day, string>(delegate(Day d)
  50:                                                                                  {
  51:                                                                                      return d.Name;
  52:                                                                                  }));
  53:              Console.WriteLine(string.Join(“, “, names.ToArray()) + “nn”);
  54:          }
  55:      }
  56:  
  57:      internal class Day : IComparable<Day>, IComparable
  58:      {
  59:          private string name;
  60:          private int ordinal;
  61:          private bool isWeekend;
  62:  
  63:          public Day(string name, int ordinal, bool isWeekend)
  64:          {
  65:              this.name = name;
  66:              this.ordinal = ordinal;
  67:              this.isWeekend = isWeekend;
  68:          }
  69:  
  70:          public string Name
  71:          {
  72:              get { return name; }
  73:              set { name = value; }
  74:          }
  75:  
  76:          public int Ordinal
  77:          {
  78:              get { return ordinal; }
  79:              set { ordinal = value; }
  80:          }
  81:  
  82:          public bool IsWeekend
  83:          {
  84:              get { return isWeekend; }
  85:              set { isWeekend = value; }
  86:          }
  87:  
  88:          public static List<Day> CreateWeek()
  89:          {
  90:              List<Day> days = new List<Day>(7);
  91:  
  92:              days.Add(new Day(“Monday”, 1, false));
  93:              days.Add(new Day(“Tuesday”, 2, false));
  94:              days.Add(new Day(“Wednesday”, 3, false));
  95:              days.Add(new Day(“Thursday”, 4, false));
  96:              days.Add(new Day(“Friday”, 5, false));
  97:              days.Add(new Day(“Saturday”, 6, true));
  98:              days.Add(new Day(“Sunday”, 7, true));
  99:  
 100:              return days;
 101:          }
 102:  
 103:          public int CompareTo(Day other)
 104:          {
 105:              return Comparer.Default.Compare(Ordinal, other.Ordinal);
 106:          }
 107:  
 108:          public int CompareTo(object obj)
 109:          {
 110:              return Comparer.Default.Compare(Ordinal, ((Day) obj).Ordinal);
 111:          }
 112:      }
 113:  }

As you can see, it took me 113 lines to achieve the required result. I am using Generics and some fancy stuff from List<>. You will need C# 2.0 to achieve similar results.

And here is the Ruby way of doing things:

   1:  class Day
   2:    attr_accessor :name, :ordinal, :is_weekend
   3:  
   4:    def initialize(name = :NotSet, ordinal = -1, is_weekend = false)
   5:      self.name, self.ordinal, self.is_weekend = name, ordinal, is_weekend
   6:    end
   7:  
   8:    def to_s
   9:      name
  10:    end
  11:  
  12:    def <=>(other_day)
  13:      self.ordinal <=> other_day.ordinal
  14:    end
  15:  
  16:    def Day.create_week
  17:      days = Array.new
  18:  
  19:      days << Day.new(:Monday, 1, false)
  20:      days << Day.new(:Tuesday, 2, false)
  21:      days << Day.new(:Wednesday, 3, false)
  22:      days << Day.new(:Thursday, 4, false)
  23:      days << Day.new(:Friday, 5, false)
  24:      days << Day.new(:Saturday, 6, true)
  25:      days << Day.new(:Sunday, 7, true)
  26:  
  27:      return days
  28:    end
  29:  
  30:  end
  31:  
  32:  def self.display_days(days, message = nil)
  33:    puts “#{message}n” if message
  34:    puts days.map{|day| day.name}.join(‘, ‘)
  35:    puts “nn”
  36:  end
  37:  
  38:  days_of_week = Day.create_week
  39:  
  40:  display_days(days_of_week, ‘Regular Order’)
  41:  
  42:  #Reverse the order of the days
  43:  days_of_week.sort!{ |a, b| (a <=> b) * -1 }
  44:  
  45:  display_days(days_of_week, ‘Reversed Order’)
  46:  
  47:  #Restore the order
  48:  days_of_week.sort!
  49:  
  50:  display_days(days_of_week, ‘Regular Order’)
  51:  
  52:  #Show work week
  53:  display_days(days_of_week.find_all{|day| !day.is_weekend}, ‘Work Week’)
  54:  
  55:  #Show weekends
  56:  display_days(days_of_week.find_all{|day| day.is_weekend}, ‘Weekend’)

As you can Ruby implementation took only 56 lines to achieve the required result.

Conclusion? I had a lot of fun playing with both languages. Give both languages a try!

13 Comments so far

  1. Jonathan Allen January 24th, 2007 11:35 pm

    You could have saved a lot of time on the C# side if you created an enumeration for the weekdays instead of making a new class.

  2. Michal Talaga January 24th, 2007 11:38 pm

    I think that choosing a language has more to do with tool support and online help (like samples found on the internet) than it has with how many lines you use to do something.
    Sure it is nice to have an alternative to C# (other than VB), but sitll I don’t think that would be a good choice for any large project.

  3. Anonymous January 25th, 2007 5:21 am

    Your C# is a tad verbose…

    using System;

    enum DayType
    {
    Monday = 0, Tuesday = 1, Wednesday = 2, Thursday = 3, Friday = 4, Saturday = 5, Sunday = 6
    };

    class Day
    {
    public DayType Type;

    public bool IsWeekend
    {
    get { return Type > DayType.Friday; }
    }

    public Day(DayType aType)
    {
    Type = aType;
    }
    }

    class Program
    {
    static void Display(Day[] aWeek, Predicate aDisplay)
    {
    foreach (Day d in aWeek)
    if (aDisplay(d) == true)
    Console.Write(d.Type.ToString() + ‘ ‘);

    Console.WriteLine();
    }

    static void Main()
    {
    Day[] week = new Day[7];

    for (int i = 0; i

  4. Jack the Ripper January 25th, 2007 9:07 am

    String[] days = { “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”, “Sunday” };

    for (int i = 0; i = 0; i–)
    Console.WriteLine(days[i]);

    for (int i = 0; i

  5. hobbit January 25th, 2007 12:19 pm

    Ick. You write c# like a java programmer. Here’s that c# one in *half* the lines used in your Ruby one :)

    using System;
    using System.Collections.Generic;

    class Program
    {
    enum DayOfWeek { Sunday, Monday,Tuesday, Wednesday, Thursday, Friday, Saturday }

    static void Main(string[] args)
    {
    List days = new List();
    for(int i =0; i !d.ToString().StartsWith(”S”)));
    DisplayDays(”Weekends”, days.FindAll(d => d.ToString().StartsWith(”S”)));
    }

    static void DisplayDays(string title, List days)
    {
    if(title != null && title != string.Empty)
    Console.WriteLine(title);
    Console.WriteLine(string.Join(”, “, days.ConvertAll(n => n.ToString()).ToArray()));
    }
    }

  6. hobbit January 25th, 2007 12:23 pm

    using System;
    using System.Collections.Generic;

    class Program
    {
    enum DayOfWeek { Sunday, Monday,Tuesday, Wednesday, Thursday, Friday, Saturday }

    static void Main(string[] args)
    {
    List days = new List<DayOfWeek>();
    for(int i =0; i < 7; i++)
    days.Add((DayOfWeek)(i));

    DisplayDays(”Original”, days);
    days.Reverse();
    DisplayDays(”Reversed”, days);
    days.Reverse();
    DisplayDays(”Original Again”, days);
    DisplayDays(”Weekdays”, days.FindAll(d => !d.ToString().StartsWith(”S”)));
    DisplayDays(”Weekends”, days.FindAll(d => d.ToString().StartsWith(”S”)));
    }

    static void DisplayDays(string title, List<DayOfWeek>days)
    {
    if(title != null && title != string.Empty)
    Console.WriteLine(title);
    Console.WriteLine(string.Join(”, “, days.ConvertAll<string>(n =>n.ToString()).ToArray()));
    }
    }

  7. Rusty March 20th, 2007 7:59 pm

    hmm. Apparently there were some _other_ c# programmers looking at your blog to see how ruby stacks up. One can’t deny the buzz about Ruby but then one can’t deny that c# is beautiful, too. I got sweaty palms when I met Anders.

  8. Lazy March 21st, 2007 9:59 am

    week = ["Monday", "Tuesday", "Wednesday", "Thursday",
    "Friday", "Saturday", "Sunday"]
    puts “Regular Order\n” + week.join(”, “)
    puts “Reversed Order\n” + week.reverse!.join(”, “)
    puts “Regular Order\n” + week.reverse!.join(”, “)
    puts “Work Week\n” + week[0..4].join(”, “)
    puts “Weekend\n” + week[5..6].join(”, “)

  9. Lazy March 23rd, 2007 4:31 am

    The six ruby lines above are hard to beat, but here’s an alternative version:

    class Array
    def to_s; self.join(’, ‘); end
    end
    week = ['Mon','Tues','Wednes','Thurs','Fri','Satur','Sun'].map{|d|d+’day’}
    puts “Regular Order\n#{week}
    Reversed Order\n#{week.reverse!}
    Regular Order\n#{week.reverse!}
    Work Week\n#{week[0..4]}
    Weekend\n#{week[5..6]}”

  10. Andreas August 7th, 2007 2:32 am

    Going for something even shorter… :)

    week = %w{Monday Tuesday Wednesday Thursday Friday Saturday Sunday}
    titles = ["Regular Order", "Reversed Order", "Regular Order", "Work Week", "Weekend"]
    values = %w{week week.reverse week week[0..4] week[5..6]}
    titles.zip(values).each { |title, value| puts “#{title}\n#{eval(value).join(’, ‘)}” }

  11. Angelo February 15th, 2008 6:51 am

    The problem with Ruby is that this is all one line, and pretty ugly:
    “titles.zip(values).each { |title, value| puts “#{title}\n#{eval(value).join(’, ‘)}” }”

    The average joe 12 pack can’t follow your logic out that far, but most folks will be able to follow the clearer (read: clearer flow, indented, tidy) C# code.

    Sometimes it is not all about what you can fit on one line, it’s about clarity and readability.

  12. Nando March 3rd, 2008 8:07 pm

    Angelo: if you want to add indentation to the Ruby example, please go ahead, no problem, indentation is totally free in Ruby (cannot say the same in Python though). This argument about “average Joe” is kind of repeated too often… I think most programmers don’t want to be considered average Joe’s, at least not me.

  13. Joe June 30th, 2008 8:27 pm

    Angelo,

    The average joe 12 pack doesn’t know how to code. If you have a basic understanding of programming and can use a web browser, you can figure that couple lines of ruby out in 5 minutes. I don’t see how you think that is more difficult to understand than ~40 lines of C#.

Leave a reply