.NET to Ruby: Types

So far in these posts on switching from .NET to Ruby we’ve looked at Classes, Namespacing, Documentation, Methods, Variables, and the Ruby Environment. We’ve covered a lot of ground. Today, we’re going to look at the data types that form the base of the Ruby language.

Even though we don’t have to explicitly declare variable data types in Ruby, they still exist. Coming from a C# background, you’ll find a lot of your familiar friends: Strings, Integers, Arrays, and Hashes. Additionally, Ruby introduces some new types: Ranges, and Symbols. We’ll be looking at those major items in this post.

Strings

Strings are a major staple of any programming language. In C# strings are written as follows:

var value = "string"

and Ruby is effectively the same:

value = "string"

The Ruby standard library offers a lot of nice functionality for manipulating strings. One of my favorite features is how Ruby does format strings. Ruby provides you with the ability to inline your strings by using the syntax #{}. In C# a format string would look something like this:

var place = "Rockey Mountains"
var feeling = "happy!"
var result = string.Format("Driving to the {0} makes me {1}", place, feeling);

In Ruby the same functionality would look like this:

place = "Rockey Mountains"
feeling = "happy!"
result = "Driving to the #{place} makes me #{feeling}"

And that’s not even the coolest part; you can put an evaluatable expression between the curly braces, and the computed result will be inlined into your string. Let’s see that in action:

puts "I am #{32 - (10 / 2)} years old" 
  #=> I am 27 years old

Ruby also offers another string delimiter in the form of a single quote. This delimeter doesn’t offer the same amount of substitution as double quotes, so it’s useful when you need to output control characters like newlines and the like:

puts 'Reduced substitutionn' #=> Reduced substitutionn
puts "More substitutionn"    #=> More substition

The second line above will have a newline added to the end of it, whereas the first line simply prints the n characters.

One important fact to note before we move on is that Ruby strings are not immutable. Now coming from a .NET background this is going to seem really bizarre because for a C# coder strings are immutable. Let’s take a look at this concept applied:

s = "string"
puts s.object_id        #=> 2156184600

s.gsub!("ing", "ong")
puts s.object_id        #=> 2156184600

Here we can see that the method gsub! actually modifies the string instance, notice specifically that the value changes but the object_id remains the same. The ! in the method signature is an indicator that calling method will modify the object it is called on, which is a Ruby convention. This is a big difference from .NET so make sure it doesn’t trip you up.

I could take up an entire post on strings, but this should be enough to wet your whistle; read through the string docs to get a better idea of what functions exist.

Integers

Ruby’s integer class is quite different from C#’s int. While they both represent the same primal data type, how the languages accomplish that representation is different. For C#, the int is known as a value type and it is a fixed size 32-bit integer. In Ruby the integer is a class that wraps, or manages two other number related classes: Fixnum and Bignum.

In more detail, a Fixnum is used when an integer value can be represented in a native machine word minus 1 bit (this is CPU specific) and a Bignum is any value outside the range of Fixnum. Now this may seem a bit confusing, but thankfully Ruby handles all of this information, including the conversion from Fixnum to Bignum in a completely transparent manner.

The useful aspect of Ruby integers is that they’re represented as objects, which means that all integers have a set of methods that can be called on them. Let me demonstrate two of those methods with an example.

Let’s take the concept of zebra striping and use C#, and Ruby to create a code snippet that produces the string “even” or “odd” for the numbers 1 – 10.

for (int i = 0; i < 10; i++) {
    var i_is = (i % 2 == 0) ? "even" : "odd"
    Console.Write(i_is);
}
10.times do |i| 
  i_is = i.even? ? "even" : "odd"
  puts i_is
end

In the above example, the code is accomplishing the same tasks, but the Ruby code is terser without losing any meaning. Also, the ruby code shows two of the methods I mentioned, even? and times. Check out their respective documentation if the method names don’t make sense.

Arrays

Let’s look at an array in C#:

var items = new string[] { "item1", "item2", "item3" }

And in Ruby you can construct an array like so:

items = [ "item1", "item2", "item3" ]

One of the areas where Ruby’s arrays vary is that they’re not strongly typed. That is, you can have an integer, string, and object in an array without Ruby complaining. While you typically won’t put an integer, string, and object into the same array, this gets useful when you have different objects that all implement the same method, and duck typing allows you to do something like this:

class ObjectA
  def hello
    "I'm object A"
  end
end
class ObjectB
  def hello
    "I'm object B"
  end
end
class ObjectC
  def hello
    "I'm object C"
  end
end

[ObjectA.new, ObjectB.new, ObjectC.new].each {|obj| puts obj.hello }
#=> "I'm object A"
#=> "I'm object B"
#=> "I'm object C"

Think about that for a second, and you can see how duck typing can really shine in Ruby.

The Array class has a ton of methods defined, which allow you to easily iterate over an array without having to write for or while loops.

The other cool feature of the Array class is that it has methods that allow an array to be treated as a stack, or a queue. For a stack it has the methods push and pop. And for a queue it has the methods push for enqueueing an item, and shift for dequeueing.

Hashes

One of the great things about Ruby is that Hashes are first class citizens. Their syntax is terse, and they enjoy an extensive set of functionality provided in the standard library.

In C# you can create a hash like this:

Hashtable ht = new Hashtable{ {"key", "value"} };

And in Ruby a hash is as easy as writting this:

ht = { :key => "value" }

Hashes are used extensively in Ruby because of how accessible they are. Adding new key/values is as simple as:

ht[:new_key] = "value"

Or say you wanted to iterate over all the key/value pairs, that code would look like this:

social_media = { :twitter => "cool", :facebook => "scary", :google_plus => "meh" }
social_media.each_pair do |key, value|
  puts "#{key} is #{value}"
end

This would output:

twitter is cool
facebook is scary
google_plus is meh

If at this point hashes don’t appear overly useful, just wait. When we talk about symbols, I’ll show you one of the reasons hashes are used frequently.

Ranges

Ranges are a fun data type that take a beginning value and an end value, composing the interval between those values. Ranges can be constructed with any object that defines the comparison operator <=> and the method succ so that the next element can be returned in the sequence. For example, we could create a range of numbers, characters, or dates:

(1..10)                         #=> 1..10
('a'..'z')                      #=> a..z
(Date.today - 5...Date.today)   #=> #<Date: 2011-11-11>...#<Date: 2011-11-16>

You’ll notice that with the date example above there are three dots used (...) instead of two (..). With ranges, two dots say “use the entire range”, and three dots say “exclude the end value.” Ranges wont’ occur too frequently, but when you need them they’re truly useful.

Symbols

Symbols are another data type that doesn’t exist in C#, but you’ll find that they’re used extensively in Ruby. The closest comparison between C# and Ruby would be to call symbols a mix between an enumerator and a constant.

Symbols are declared by prefacing a word or string with a colon:

:name           #=> :name
:"a symbol"     #=> :"a symbol"

The seconde example is rarely used, if at all. One of the most common usages of symbols is for option hashes which are typically found in frameworks like Rails. Here’s an example:

def make_link(href, opts = {})
  title = opts[:title] || href

  "<a href="#{href}">#{title}</a> 
end

puts make_link("http://www.sitepoint.com", {:title => "How To Be An Awesome Rubyist"})
  #=> <a href="http://www.sitepoint.com">How To Be An Awesome Rubyist</a>

puts make_link("http://www.sitepoint.com")
  #=> <a href="http://www.sitepoint.com">http://www.sitepoint.com</a>

You can see in the above code, we’re using the symbol :title as an optional value for the method make_link. Major frameworks in Ruby tend to use this convention since it cleans up the method interface, and makes it easier to add/remove optional parameters. In this way you can change a method signature (add or remove parameters) without causing every piece of code reliant on that method to break.

An important point to address is why you would want to use symbols over a string in Ruby. One of the main reasons is that a symbol always references the same object, whereas each string instance is a different object (remember Ruby strings are mutable.) Let’s take a look at that in practice:

puts :symbol.object_id   #=> 442248
puts :symbol.object_id   #=> 442248
puts "string".object_id  #=> 2156234340
puts "string".object_id  #=> 2156197521

Notice how the object_id varies for the two string instances, but is the same for :symbol. This supports the concept of mutable strings addressed in the string section.

At this point, we’ve looked at a lot of code in comparing C# to Ruby. Today’s post covered the differences between the Ruby and C# data types. We explored strings, integers, arrays, hashes, ranges, and symbols. I think you’re ready to take a C# program and convert it into a Ruby program. I would suggest starting with something like FizzBuzz, and work your way up from there. The best way to learn a new language is write programs in that language.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • https://twitter.com/#!/anithri Scott M Parrish

    A few more things about hashs.

    1. The Hash example implies you use symbols as keys for hashes. While this is a common pattern in ruby, the fact is that you can use any object as a key: Strings, Numbers, and any other type of arbitrary object can be used as keys.

    2. Hash has a wonderful and underused feature called .default this allows you to set a value to returned if you ask for a the value for a nonexistant key.
    h = {“abc” => 123, “def” => “456”}
    h.default = 789
    h["abc"] #=> 123
    h["xyz"] #=> 789

    you can also use fetch which can be used with a specific value or block to generate a missing value.
    h.fetch(“abc”,”missing abc”) #=> 123
    h.fetch(“ghi”,”000″) #=> “000”
    h.fetch(“jkl”) {|k| “No value for #{k}”} #=> “No value for jkl”

    3. You can test to see if a hash contains a specific key
    h.has_key?(“abc”) #=> true
    h.has_key?(“pqr”) #=> false

    4. Hash has an each_key and a each_value that provide an iterator over all of the keys or all of the values in a hash.

    Great series so far, keep up the good work.