Meet six misunderstood Ruby features

Learn about Ruby features likely to trip up C++ programmers

If you're a C++ programmer and need to work in Ruby, you have a bit of learning to do. This article discusses six Ruby features that the Ruby newbie is likely to misunderstand, especially if he or she comes from a similar-but-not-quite environment like C++ :

The Ruby class hierarchy

Singleton methods in Ruby

The self keyword

keyword The method_missing method

method Exception handling

Threading

Note: All code in this article was tested and based on Ruby version 1.8.7.

Class hierarchy in Ruby

Class hierarchy in Ruby can be tricky. Create a class of type Cat and start to play with its hierarchy (see Listing 1).

Listing 1. Implicit class hierarchy in Ruby

irb(main):092:0> class Cat irb(main):093:1> end => nil irb(main):087:0> c = Cat.new => #<Cat:0x2bacb68> irb(main):088:0> c.class => Cat irb(main):089:0> c.class.superclass => Object irb(main):090:0> c.class.superclass.superclass => nil irb(main):091:0> c.class.superclass.superclass.superclass NoMethodError: undefined method `superclass' for nil:NilClass from (irb):91 from :0

All objects in Ruby (even the user-defined objects) are descendants of the Object class, as is obvious from Listing 1. This is in sharp contrast to C++ . There's nothing like a plain datatype—for example, C/C++ int or double . Listing 2 shows the class hierarchy for the integer 1.

Listing 2. Class hierarchy for 1

irb(main):100:0> 1.class => Fixnum irb(main):101:0> 1.class.superclass => Integer irb(main):102:0> 1.class.superclass.superclass => Numeric irb(main):103:0> 1.class.superclass.superclass.superclass => Object

So far so good. Now you know that classes themselves are objects of type Class . Class in turn is ultimately derived from Object , as demonstrated in Listing 3, with the Ruby built-in String class.

Listing 3. Class hierarchy for classes

irb(main):100:0> String.class => Class irb(main):101:0> String.class.superclass => Module irb(main):102:0> String.class.superclass.superclass => Object

Module is the base class for Class , and it comes with the caveat that you cannot instantiate user-defined Module objects directly. If you don't want to get into Ruby internals, it's safe to consider Module having similar characteristics to a C++ namespace: You can define your own methods, constants, and so on. You include a Module inside a Class , and voilà, all the elements of the Module are now magically the elements of the Class . Listing 4 provides an example.

Listing 4. Modules cannot be directly instantiated and can be used only with classes

irb(main):020:0> module MyModule irb(main):021:1> def hello irb(main):022:2> puts "Hello World" irb(main):023:2> end irb(main):024:1> end irb(main):025:0> test = MyModule.new NoMethodError: undefined method `new' for MyModule:Module from (irb):25 irb(main):026:0> class MyClass irb(main):027:1> include MyModule irb(main):028:1> end => MyClass irb(main):029:0> test = MyClass.new => #<MyClass:0x2c18bc8> irb(main):030:0> test.hello Hello World => nil

Here's the recap, then: When you write c = Cat.new in Ruby, c is an object of type Cat that is derived from Object . The Cat class is an object of type Class , which is derived from Module , which is in turn derived from Object . Both the object and its type are thus valid Ruby objects.

Singleton methods and editable classes

Now, look at singleton methods. Suppose you want to model something akin to the human society in C++ . How would you do it? Have a class called Human , and then have millions of Human objects? That's more like modeling a zombie society; each human must have some unique characteristic. Ruby's singleton methods come in handy here, as explained in Listing 5.

Listing 5. Singleton methods in Ruby

irb(main):113:0> y = Human.new => #<Human:0x319b6f0> irb(main):114:0> def y.paint irb(main):115:1> puts "Can paint" irb(main):116:1> end => nil irb(main):117:0> y.paint Can paint => nil irb(main):118:0> z = Human.new => #<Human:0x3153fc0> irb(main):119:0> z.paint NoMethodError: undefined method `paint' for #<Human:0x3153fc0> from (irb):119

Singleton methods in Ruby are methods only associated with a particular object and not available to the general class. They are prefixed with the object name. In Listing 5, the paint method is specific to the object y and y alone; z.paint results in an undefined method error. You can figure out the list of singleton methods in an object by calling singleton_methods :

irb(main):120:0> y.singleton_methods => ["paint"]

There's yet another way of defining singleton methods in Ruby. Consider the code in Listing 6.

Listing 6. Yet another way of creating singleton methods

irb(main):113:0> y = Human.new => #<Human:0x319b6f0> irb(main):114:0> class << y irb(main):115:1> def sing irb(main):116:1> puts "Can sing" irb(main):117:1> end irb(main):118:1>end => nil irb(main):117:0> y.sing Can sing => nil

Listing 5 also opens interesting possibilities about adding new methods to user-defined classes and to built-in Ruby existing classes like String . That's impossible in C++ unless you have access to the source code for the classes that you use. Look into the String class once more (Listing 7).

Listing 7. Ruby allows you to modify an existing class

irb(main):035:0> y = String.new("racecar") => "racecar" irb(main):036:0> y.methods.grep(/palindrome/) => [ ] irb(main):037:0> class String irb(main):038:1> def palindrome? irb(main):039:2> self == self.reverse irb(main):040:2> end irb(main):041:1> end irb(main):050:0> y.palindrome? => true

Listing 7 clearly illustrates how you can edit an existing Ruby class to add the methods of your choice. Here, I added the palindrome? method to the String class. Ruby classes are therefore editable at run time—a powerful property.

Now that you have some idea of Ruby's class hierarchy and singletons, let's move on to the self . Note that I used self while defining the palindrome? method.

Discovering self

The most common use of the self keyword is perhaps to declare a static method in a Ruby class, as in Listing 8.

Listing 8. Using self to declare class static methods

class SelfTest def self.test puts "Hello World with self!" end end class SelfTest2 def test puts "This is not a class static method" end end SelfTest.test SelfTest2.test

As you can see in the output from Listing 8—shown in Listing 9—you cannot invoke non-static methods without objects. The behavior resembles C++ .

Listing 9. Error when non-static methods are called without objects

irb(main):087:0> SelfTest.test Hello World with self! => nil irb(main):088:0> SelfTest2.test NoMethodError: undefined method 'test' for SelfTest2:Class from (irb):88

Before moving on to more esoteric uses and meanings of self , note that you can also define a static method in Ruby by prefixing the class name before the method name:

class TestMe def TestMe.test puts "Yet another static member function" end end TestMe.test # works fine

Listing 10 offers a more interesting but rather difficult-looking use of self .

Listing 10. Using meta-class to declare static methods

class MyTest class << self def test puts "This is a class static method" end end end MyTest.test # works fine

This code defines test as a class static method in a slightly different way. To understand what's happening, you need to look at the class << self syntax in some detail. class << self … end creates a meta-class. In the method lookup chain, the meta-class of an object is searched before accessing the base class of the object. If you define a method in the meta-class, it can be invoked on the class. This is similar to the notion of static methods in C++ .

Is it possible to access a meta-class? Yes: Just return self from inside class << self … end . Note that in a Ruby class declaration, you are under no obligation to put only method definitions. Listing 11 shows the meta-class.

Listing 11. Getting hold of the meta-class

irb(main):198:0> class MyTest irb(main):199:1> end => nil irb(main):200:0> y = MyTest.new => #< MyTest:0x2d43fe0> irb(main):201:0> z = class MyTest irb(main):202:1> class << self irb(main):203:2> self irb(main):204:2> end irb(main):205:1> end => #<Class: MyTest > irb(main):206:0> z.class => Class irb(main):207:0> y.class => MyTest

Coming back to the code in Listing 7, you see that palindrome is defined as self == self.reverse . In this context, self is no different from C++ . The methods in C++ and likewise in Ruby need an object to act upon to modify or extract state information. self refers to that object here. Note that public methods can optionally be called by prefixing the self keyword to indicate the object on which the method is acting, as in Listing 12.

Listing 12. Using self to invoke methods

irb(main):094:0> class SelfTest3 irb(main):095:1> def foo irb(main):096:2> self.bar() irb(main):097:2> end irb(main):098:1> def bar irb(main):099:2> puts "Testing Self" irb(main):100:2> end irb(main):101:1> end => nil irb(main):102:0> test = SelfTest3.new => #<SelfTest3:0x2d15750> irb(main):103:0> test.foo Testing Self => nil

You cannot call private methods in Ruby with the self keyword prefixed. For a C++ developer, this might get pretty confusing. The code in Listing 13 clearly shows that self cannot be used with private methods: The call to the private method must only be made with an implicit object.

Listing 13. self cannot be used with private method invocation

irb(main):110:0> class SelfTest4 irb(main):111:1> def method1 irb(main):112:2> self.method2 irb(main):113:2> end irb(main):114:1> def method3 irb(main):115:2> method2 irb(main):116:2> end irb(main):117:1> private irb(main):118:1> def method2 irb(main):119:2> puts "Inside private method" irb(main):120:2> end irb(main):121:1> end => nil irb(main):122:0> y = SelfTest4.new => #<SelfTest4:0x2c13d80> irb(main):123:0> y.method1 NoMethodError: private method `method2' called for #<SelfTest4:0x2c13d80> from (irb):112:in `method1' irb(main):124:0> y.method3 Inside private method => nil

Because everything in Ruby is an object, here's what you get when you invoke self on the irb prompt:

irb(main):104:0> self => main irb(main):105:0> self.class => Object

The moment you launch irb , the Ruby interpreter creates the main object for you. This main object is also known as the top-level context in the Ruby-related literature.

Enough of self . Let's move on to dynamic methods and the method_missing method.

The mystery behind method_missing

Consider the Ruby code in Listing 14.

Listing 14. method_missing in action

irb(main):135:0> class Test irb(main):136:1> def method_missing(method, *args) irb(main):137:2> puts "Method: #{method} Args: (#{args.join(', ')})" irb(main):138:2> end irb(main):139:1> end => nil irb(main):140:0> t = Test.new => #<Test:0x2c7b850> irb(main):141:0> t.f(23) Method: f Args: (23) => nil

Clearly, if voodoo is your thing, Listing 14 should bring smile to your face. What happened here? You created an object of type Test , and then called t.f with 23 as an argument. But Test did not have f as a method, and you should get a NoMethodError or similar error message. Ruby is doing something fascinating here: Your method calls are being intercepted and handled by method_missing . The first argument to method_missing is the method name that's missing—in this case, f . The second and last argument is *args , which captures the arguments being passed to f . Where could you use something like this? Among other options, you could easily forward method calls to an included Module or a component object without explicitly providing a wrapper application programming interface for each call in the top-level class.

Take a look at some more voodoo in Listing 15.

Listing 15. Using the send method to pass arguments to a routine

irb(main):142:0> class Test irb(main):143:1> def method1(s, y) irb(main):144:2> puts "S: #{s} Y: #{y}" irb(main):145:2> end irb(main):146:1> end => nil irb(main):147:0>t = Test.new irb(main):148:0> t.send(:method1, 23, 12) S: 23 Y: 12 => nil

In Listing 15, class Test has a method called method1 defined. However, instead of calling the method directly, you make a call to the send method. send is a public method of the class Object and therefore available for Test (all classes are derived from Object , remember). The first argument to the send method is a symbol or string that denotes the method name. What can the send method do that in the normal course you cannot? You can access private methods of a class using the send method. Of course, whether this is a good feature to have remains debatable. Look at the code in Listing 16.

Listing 16. Accessing class private methods

irb(main):258:0> class SendTest irb(main):259:1> private irb(main):260:1> def hello irb(main):261:2> puts "Saying Hello privately" irb(main):262:2> end irb(main):263:1> end => nil irb(main):264:0> y = SendTest.new => #< SendTest:0x2cc52c0> irb(main):265:0> y.hello NoMethodError: private method `hello' called for #< SendTest:0x2cc52c0> from (irb):265 irb(main):266:0> y.send(:hello) Saying Hello privately => nil

Throw and catch are not what they seem

If you come from a C++ background like I do and have a tendency to try writing exception-safe code, then you will probably start feeling at home the moment you see that Ruby has the throw and catch keywords. Unfortunately, throw and catch have a completely different meaning in Ruby.

Ruby typically handles exceptions using begin…rescue blocks. Listing 17 provides an example.

Listing 17. Exception handling in Ruby

begin f = File.open("ruby.txt") # .. continue file processing rescue ex => Exception # .. handle errors, if any ensure f.close unless f.nil? # always execute the code in ensure block end

In Listing 17, if something bad happens while trying to open the file (maybe a missing file or an issue with file permissions), the code in the rescue block runs. The code in the ensure block always runs, irrespective of whether any exceptions were raised. Note that the presence of the ensure block after the rescue block is optional, however. Also, if an exception must be thrown explicitly, then the syntax is raise <MyException> . If you choose to have your own exception class, you might want to derive the same from Ruby's built-in Exception class to take advantage of existing methods.

The catch-and-throw facility in Ruby is not really exception handling: You can use throw to alter program flow. Listing 18 shows an example using throw and catch .

Listing 18. Throw and catch in Ruby

irb(main):185:0> catch :label do irb(main):186:1* puts "This will print" irb(main):187:1> throw :label irb(main):188:1> puts "This will not print" irb(main):189:1> end This will print => nil

In Listing 18, when the code flow hits the throw statement, the execution is interrupted, and the interpreter begins looking for a catch block that handles the corresponding symbol. Execution is restarted from where the catch block ends. Look at the example of throw and catch in Listing 19: Note that you can easily spread catch and throw statements across functions.

Listing 19. Exception handling in Ruby: nested catch blocks

irb(main):190:0> catch :label do irb(main):191:1* catch :label1 do irb(main):192:2* puts "This will print" irb(main):193:2> throw :label irb(main):194:2> puts "This won't print" irb(main):195:2> end irb(main):196:1> puts "Neither will this print" irb(main):197:1> end This will print => nil

Some people have gone to the extent of saying that Ruby takes the C goto madness to altogether new heights with its catch and throw support. Given that there could be several nested layers of functions with catch blocks possible at every level, the goto madness analogy does seem to have some steam here.

Threads in Ruby can be green

Ruby version 1.8.7 does not support true concurrency. It really, truly does not. But you have the Thread construct in Ruby, you say. Right you are. But that Thread.new does not spawn a real operating system thread every time you make a call to the same. What Ruby supports is green threads: The Ruby interpreter uses a single operating system thread to handle the workload from multiple application-level threads.

This "green thread" concept is useful while some thread is waiting on some I/O to occur, and you can easily schedule a different Ruby thread to make good use of the CPU. But this construct cannot use a modern multi-core CPU. (Wikipedia provides an excellent piece that explains what green threads are. See Related topics for a link.)

This final example (see Listing 20) proves the point.

Listing 20. Multiple threads in Ruby

#!/usr/bin/env ruby def func(id, count) i = 0; while (i < count) puts "Thread #{i} Time: #{Time.now}" sleep(1) i = i + 1 end end puts "Started at #{Time.now}" thread1 = Thread.new{func(1, 100)} thread2 = Thread.new{func(2, 100)} thread3 = Thread.new{func(3, 100)} thread4 = Thread.new{func(4, 100)} thread1.join thread2.join thread3.join thread4.join puts "Ending at #{Time.now}"

Assuming that you have the top utility on your Linux® or UNIX® box, run the code in a terminal, get the process ID, and run top –p <process id> . When top starts, press Shift-H to list the number of threads running. You should see only a single thread confirming what you knew anyway: concurrency in Ruby 1.8.7 is a myth.

All that said, green threads are not bad. They are still useful in heavy-duty I/O-bound programs, not to mention that this approach is probably the most portable across operating systems.

Conclusion

This article covered quite a few areas:

Notions of class hierarchy in Rub

nSingleton methods

Deciphering the self keyword and method_missing method

keyword and method Exceptions

Threading

Notwithstanding its quirks, Ruby is fun to program in and extremely powerful in its ability to do a lot with minimum code. No wonder, then, that large-scale applications like Twitter are using Ruby to harness their true potential. Happy coding in Ruby!

Downloadable resources

Related topics