Zend certified PHP/Magento developer

RubySource: .NET to Ruby: Classes

In the previous post of this series .NET to Ruby: The Ruby Environment, we went through the fundamental tools that made up Ruby. If you recall we talked about running Ruby on the command line, using IRB, we wrote our first Hello World program, and figured out what was going on below the covers.

In this post we’ll look to compare a fundamental object oriented feature: Classes. Yup that’s it. This post started as classes, methods, and variables, but it grew too big – there’s a lot to cover when discussing classes! So let’s dive in.

Classes

Classes exist within Ruby just like .NET, and their definition stays the same. In both

Ruby and .NET classes are used to encapsulate (or group) pieces of related data and methods into a succinct object

In both cases we can instantiate a class and get an instance of it. Ruby and .NET use the new keyword to create object instances, but the syntax differs slightly:

// In C#
var baz = new FooBar();
# In Ruby
baz = FooBar.new

To actually define a class, in C# we’d do that like this:

public class FooBar {
    // Class implementation
}

And in Ruby a class looks like this:

class FooBar
  # Class implementation
end

Really simple and straight forward, the difference to notice is that Ruby’s class definition is missing scope. And class scope is one area where Ruby differs significantly from .NET, because Ruby doesn’t allow for private, protected, or internal classes. All classes within Ruby are public.

Why Are Ruby’s Classes all Public?

Ruby has public classes because fundamentally all of Ruby’s classes are Open Classes. What this means is that I can break open the String class (or any other) and add functionality to it. Here’s an example:

class String
  def remove_vowels
    self.gsub(/[aeiou]/, '')
  end
end
puts "this is a sentence".remove_vowels #= ths s  sntnc

Now before anyone jumps on Ruby for allowing such an atrocity, let’s point out that .NET allows for the same functionality in the form of Extension Methods. Let’s write the same code in .NET:

static class StringExtensions
{
    public static string ReplaceVowels(this string value)
    {
        return new Regex("[aeiou]").Replace(value, string.Empty);
    }
}

The only place where Ruby’s Open Classes, and .NET’s Extension functionality differ is that with Ruby you can open a class and define class methods, whereas with .NET you cannot define a class method extension.

Since this series on transitioning from .NET to Ruby isn’t about starting flame wars, I’ll leave it to you to determine if Open Classes, and Extensions are worth the class encapsulation violation that they introduce (put your opinion in the comments if you’re especially brave.)

For those of you that want to look at examples of well applied open classes, meander over to GitHub, and have a look at Rails core_ext.

Inheritence

Inheritence in Ruby is just like .NET. With it we can define a superclass, and then inherit from the superclass to create subclasses. The subclasses inherit all the data and methods of the superclass as we’d expect. In C# we’d use inheritence like this:

public class Mammal {
    // Methods  data
}
public class Human : Mammal {
}

In Ruby inheritence looks like this:

class Mammal
end
class Dog  Mammal
end

With Ruby the less than symbol is used to denote the inheritence.

Interfaces

Let’s talk interfaces. Interfaces are another feature that Ruby doesn’t have compared to .NET, and this is because Ruby is duck typed. The basic definition of duck typing is:

If it walks like a duck, swims like a duck, and talks like a duck, then it must be a duck.

Now if you have no idea what duck typing is, that just made things worse. At it’s core duck typing allows you to call a method on any object instance regardless of type, and if that instance responds to the method the instance will execute it. Let’s look at an example:

class Duck
  def talk
    puts "quack"
  end
end
class Dog
  def talk
    puts "woof"
  end
end
duck = Duck.new
duck.talk         #= quack
dog = Dog.new
dog.talk          #= woof

In this example we’re using a Duck instance, and a Dog instance and calling the talk method on the instance. Since both instances will respond to talk this program will execute without throwing an error. But what if an instance doesn’t have a method that’s called on it?

class Truck
end
truck = Truck.new
truck.talk
   #= NoMethodError: undefined method `talk' for Truck:0x1011d1620

As can be seen from the example, a NoMethodError is raised when talk is called on truck. This is duck typing: Regardless of the underlying type, if an instance can respond to a method it will, if it can’t it will error. So why does duck typing allow Ruby to forgo interfaces? Because Ruby doesn’t care about types.

In .NET interfaces are used so that we can pass object instances of different types into a method and the compiler will check whether that instance type conforms to the interface. This allows us to define our expectations for an instance without saying how those expectations ought to be met. But because Ruby is duck typed, every instance can be passed into that method – you run the risk of getting a NoMethodError, but that is part of the risk/reward trade off when working with a dynamic language.

To summarize, because Ruby is a dynamic language that doesn’t deal with type safety checking, and because it is duck typed, Ruby doesn’t define a formal, code based way to declare an interface.

Now don’t get me wrong, interfaces are an important concept and they’ve been invented for a reason. Ruby takes a different approach in that interfaces are informally defined in the form of documentation. Rack is one example of code that formally defines an interface (they call it a protocol) that any code using Rack must conform to.

You see Ruby, and Ruby programmers like the “Don’t Repeat Yourself” principle. So why would you write an interface in code, and then write it into your documentation as well? That’s duplicated effort. Instead write really good documentation for your code, explain your interfaces and their rational, and leave it to the consumer of your code to implement the interface.

With all that said, if you really wanted to, you could define a Ruby interface within code. It’s not something that most Rubyists would do, since it goes against Ruby conventions but you can do it.

The final point to make on Duck typing is that it has a lot of benefit to it. We’ll look at two of those benefits later when we touch on writing mocks for unit test, and when doing meta-programming.

Abstract Classes

Moving onto Abstract classes, let’s outline a basic definition:

A class that is marked Abstract dictates that a superclass cannot be instantiated and that it must instead be instantiated as a subclass

The implications of this definition are that the functionality declared in the superclass is passed on to the subclass. This definition is important because Ruby doesn’t have a concept of abstract classes like .NET does.

Instead Ruby implements something called Mixins. Mixins are a lot like abstract classes in that they can be used to define methods and data that can be added into a class. They can’t be instantiated directly, but instead are included into an existing class. Here’s a brief example:

  module Cheerful
    def greeting
      puts "It's nice to meet you!"
    end
  end
  class Man
    include Cheerful
  end
  bill = Man.new
  bill.greeting     #= It's nice to meet you!

For this code we declare a module called Cheerful. Modules are also used for namespacing which I’ll elaborate on in another post. We then use the method include to mixin the Cheerful module with the Man class. By mixing Cheerful into Man we’re able to call any of the methods, or access any of the data defined within Cheerful.

Now this is a really basic example, but the power in Mixins comes from our ability to mixin any number of modules that we want to. Effectively mixins allow you to write common code once – like code for enumerating over collections – and have it applied across a broad number of classes (if you read the documentation for Enumerable, there’s an interface definition there too!)

So while Ruby doesn’t use Abstract classes, it instead provides Mixins which can be used to achieve the same end as Abstract classes.

And with that this post on classes is complete. There was a lot of ground covered in this post. We touched on Class implementation, Open Classes, Inheritence, Interfaces, Duck Typing, Abstract Classes, and Mixins. In the next post on Transitioning from .NET to Ruby, we’ll look into how Methods and Variables work within Ruby.

As always comments, and discussion are welcome and appreciated!