This post was migrated from Justin’s personal blog, 'Codethinked.com.' Views, opinions, and colorful expressions should be taken in context, and do not necessarily represent those of Simple Thread (and were written under the influence of dangerous levels of caffeination).

Click here to view the entire IronRuby via C# series

In the previous part of my series about learning Ruby using C# we discussed constructors, instance methods, parameters, and then touched on blocks a bit at the end. Well, in this post we are going to delve a bit further into classes by talking about static methods (class methods in Ruby) , a bit more info about parameters, and then finish it up with some tidbits about conditionals and loops.

To start it off, lets look at some quick static methods in our Person class. Lets say we want to define a method that returns the total count of Person objects that have been instantiated. In C#, our class would look like this (notice that I have left out the rest of the class for brevity):

public class Person
{
    private static int instanceCount = 0;
    
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {            
        this.FirstName = firstName;
        this.LastName = lastName;
        instanceCount++;
    }    

    public static int InstanceCount()
    {
        return instanceCount;
    }
}

So, as you see, we just have a static variable named instanceCount that tracks the number of instances created. We then have a static number that allows us to retrieve this number. In Ruby we actually have several ways to define a method like this. One is to use “self” and one other (there are several) is to use the class name (in our case “Person”). We are going to use “self” in our example, but you can just replace that with the class name if you like:

class Person
    @@instance_count = 0
    
    attr_accessor :first_name
    attr_accessor :last_name
    
    def initialize(first_name, last_name)
        self.first_name = first_name
        self.last_name = last_name
        @@instance_count += 1
    end
    
    def self.instance_count
        return @@instance_count
    end
end

Here you will notice the static variable from the previous post, and we have our corresponding static method. Pretty cool, huh? Looks extremely similar to C# so far. You would consume this just as you would in C#:

puts Person.instance_count

Okay, so we discussed static methods, and now I have a few more quick things that I want to show you about parameter passing in Ruby. The first thing is that Ruby supports default parameters! I have always wanted default paramters in C#, and I have heard all of the arguments about just using overloads, and I just don’t buy it. I want me some default variables, and I want them now! So, in Ruby if I wanted to default the parameters in my constructor, I could just do this:

def initialize(first_name = "John", last_name = "Doe")
    self.first_name = first_name
    self.last_name = last_name
    @@instance_count += 1
end

So great! Now, I can call the “new” method without any parameters and it will default one or both parameter values for me. So doing this…

person = Person.new
puts person.first_and_last_name

Results in “John Doe” being written to the console. In order to get the same effect with C#, we’d have to define three constructors:

public Person(): this("John", "Doe") { }
public Person(string firstName) : this(firstName, "Doe") { }
public Person(string firstName, string lastName)
{            
    this.FirstName = firstName;
    this.LastName = lastName;
    instanceCount++;
}

Not too terrible, but defaults would have been nice!

Now, there is one other thing that Ruby does with parameters and that is to allow hashes to be passed as parameter lists. Since we have yet to discuss hashes, I am going to skip this for now, but we will come back to it later on!

Lets take a look at a boolean in Ruby. In C# we just declare our boolean like this:

bool isValid = false;

And in Ruby, since types are implicit, we would just do this:

is_valid = true

So, what about an if statement? In C#, our if statement would look like this:

if (isValid){
    //do something
}

And our Ruby if would look almost the same:

if (is_valid)
    #do something
end

But Ruby supports the unless statement… unless?

unless (is_valid)
    #do something
end

Yep, unless. It is the negation of “if”. This would run the code block only if “is_valid” is false (aka not true). We would just do this in C# (which also works in Ruby):

if (!isValid){
    //do something
}

But the fun doesn’t stop there! Ruby also less us put the “if” and “unless” statements at the end of a line! For example, I could do this:

puts "It is valid!" if is_valid

Very interesting. It now reads almost like an English sentence, and does it exactly what it sounds like. It writes out “It is valid!” if “is_valid” is true. We can also do the same with “unless”:

puts "It is not valid!" unless is_valid

Pretty sweet. So now that you have seen these statements, you can also be aware that Ruby supports pretty much all of the normal boolean operators that C# does, and so I’m not going to go through them one by one. We will use them in our next section though.

On with the loops! Ruby supports many different looping mechanisms like “while”, “until”, “do..while”, “do..until”, and “for”. A C# for loop that looks like this:

for (int i = 1; i <= 10; i++){
    Console.WriteLine(i);
}

Would look like this in Ruby:

for number in 1..10
    puts number
end

The biggest difference is that in Ruby, these classic looping constructs are almost never used! I’m not even going to bother going through them! In Ruby the idea that you most often see is that objects themselves should be responsible for their own looping. This is evident in the use of the “each” method.

You have probably seen C#’s “foreach” statement quite a bit:

foreach (string name in names){
    Console.WriteLine(name);
}

Ruby has a similar construct:

names.each do |name|
    puts name
end

But if you combine that with Ruby’s excellent support for ranges (yes, C# has a Range class as well, Ruby’s is just easier to use) then you can do the above for loop like this:

(1..10).each do |num|
    puts num
end

And that is the way that you will see it done quite a bit. In fact, if you had done “(1…10)” then it does 1 to 10 exclusive (meaning only 1 to 9). Since we are starting at 1, you could also write it like this:

10.times do |num|
    puts num + 1
end

We had to add in the “+ 1” since the “times” method starts at 0. But it does execute it 10 times. Again, we are starting to see a recurring pattern with Ruby. And that pattern is that there are 18 million ways to do everything! If you don’t like choice, then Ruby may not be the language for you!

And there you have it folks. I am going to quit there for now and let you soak it all up. We have covered some static methods, default parameter goodness, boolean madness, and finally a little bit of looping. In the next post I’ll talk a bit more about Ranges, and then delve into the hash tables (or associative arrays) that we mentioned earlier. I will also discuss arrays in Ruby and why they are different from C# arrays.

I hope you enjoyed the post, and please let me know if there is anything that you have questions about or would like to see!

4 Comments

Joey Beninghove

This is good stuff man. One cool thing about the Ruby language as well is that symbols are allowed in method names.

For example, a couple of the idioms that I’ve seen is that person.is_valid would normally be written as person.is_valid? Which actually improves the readability that much more. I’ve also seen !’s used for alternate implementations of methods that are critical or will throw exceptions… like person.destroy! or person.validate!

Keep up the good posts!

Reply
Justin Etheredge

@Joey Yeah, it is a shame that Ruby doesn’t support putting question marks at the end of variables. But I will try to work in the question mark and exclamation marks into a future post. Thanks for the tip!

Reply
Zehra Altug

Testing comment from home computer; why I am not successful posting comment to Justin’s blog? I like the spell check in the comment window.

Reply
Keith Corlett

I think it’s worth noting that, as of .NET 4.0 (VS2010), C# also supports optional parameters… and the name of the parmeter name may be used in the invocation… either to identify the parameter, or just to make the code more self-documenting (which I find especially good for booleans and magic-numbers.

public Person(string firstName=”John”, string lastName=”Doe”) {
this.FirstName = firstName;
this.LastName = lastName;
}

…..

new Person(lastName:”Deer”);

…..

// This is pretty cryptic. I’d have to look at the API to see what those parameters mean…
doc.Print(297, 210, true, true, true);

// whereas this is self-explanatory
doc.Print(paperHeightInMillimetres:297, paperWidthInMillimetres:210, shrinkToFitPage:true, doubleSided:true);

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *