1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

References to Methods in Ruby

By

References to Methods in Ruby

In C or C++, you may be familiar with the concept of function pointers. A pointer is an integer that refers to a memory location. A pointer is usually paired with a type that describes what is being pointed to (with the exception of the void pointer). This can either be a value, a struct or object of some kind, or a function. Functions in C, C++ and other compiled languages are concrete things. Not like in Ruby where methods are somewhere out there in the aether. You can't take the address of a method in Ruby, can you? Or hold a reference to a method? Actually, you can.

In C, function pointers are simple. The C compiler has compiled that function into machine code and that code is loaded into memory at the address specified by the pointer. Additional information about that function is defined by the type of function pointer, such as the return value and type and number of arguments. In Ruby, method references are not quite as easy. Methods in Ruby never exist by themselves. In essence, all methods are instance methods. All methods must be paired with an object. This is why it's not possible to simply take the address of or a reference to a method in Ruby. But there is something else you can do.

Say you wanted to make a callback. You have an instance of the Monkey class and you want it to call the eat_banana method whenever a bell is rung (a similar experiment to Pavlov's dog, only with more poo flinging). The problem is that the code that rings the bell doesn't know anything about the monkey. Here's how you might solve this problem if you didn't know about the Method class (and, in fact, are solving the problem in much the same way the Method class solves it).


#!/usr/bin/env ruby

class Monkey
  def initialize
    @bananas = 3
  end

  def eat_banana
    if @bananas > 0
      @bananas -= 1
      puts "The monkey eats a banana"
    else
      puts "The monkey screams, it has no bananas left"
    end
  end
end

# When the bell is run, call a callback
class Bell
  def initialize(callback)
    @callback = callback
  end

  def ring
    puts "RING RING RING!"
    @callback.call
  end
end

m = Monkey.new
b = Bell.new( proc{ m.eat_banana } )

4.times do
  b.ring
end

The Monkey class is simple. It knows how many bananas it has and, when you tell it to eat a banana, it will either eat one or scream (hungry monkeys are very grouchy). The Bell class is equally as simple, when it's rung it will call a callback. Note that, by design, the bell doesn't know what it's achieving, it's merely a trigger. The clever bit here comes when creating the Bell object, a proc object (a closure) is created to serve as the callback. This proc object knows about the monkey, and knows the monkey should eat a banana.

But what this proc object really does here is to serve as a long winded reference to a method. The proc only does one thing, call a method on an object. Finally, here's where the Method class comes in.

All we need to do here is change a single line. Instead of making a proc object, we just call the Object#method method. This method essentially does the same thing, return a callable object that holds a reference to the object and the name of the method you want to call.


b = Bell.new( m.method(:eat_banana) )

The Method object returned by the Object#method method can be seen as a type of proc, lambda, block, etc. It follows all of the callable object duck typing rules. In addition, Method objects have a few useful methods itself that can tell you about the object and method it refers to.

  • arity - The "arity" of a method is the number of arguments it can take. This will return, as a Fixnum, the number of arguments the method expects. Remember that calling a method with the incorrect number of arguments is an error in Ruby, it will raise an exception.
  • to_s - Outputs a string representation of the type of object to refers to and the name of the method. The Method object created in the above example will produce #.
  • name - Returns the name of the method referred to. The above example will return :eat_banana.
  • owner - Returns the type of the object referred to.
  • receiver - Returns a reference to the object referred to.
  • unbind - This one can be use to do a bit of method-fu. The unbind method will return an UnboundMethod object which can be then bound to another object of the same type. This seems rather useless at first, but it allows you to change the object a Method object refers to without having to change all of the references to the Method object.
  1. About.com
  2. Technology
  3. Ruby
  4. Advanced Ruby
  5. References to Methods in Ruby

©2014 About.com. All rights reserved.