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
Leave a reply
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.
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.
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
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
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()));
}
}
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()));
}
}
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.
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(”, “)
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]}”
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(’, ‘)}” }
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.
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.
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#.