Ruby Programming/Syntax/Method Calls

From Wikibooks, open books for an open world
< Ruby Programming‎ | Syntax
Jump to: navigation, search

A method in Ruby is a set of expressions that returns a value. With methods, one can organize their code into subroutines that can be easily invoked from other areas of their program. Other languages sometimes refer to this as a function. A method may be defined as a part of a class or separately.

Method Calls[edit]

Methods are called using the following syntax:

method_name(parameter1, parameter2,…)

If the method has no parameters the parentheses can usually be omitted as in the following:

method_name

If you don't have code that needs to use method result immediately, Ruby allows to specify parameters omitting parentheses:

results = method_name parameter1, parameter2           # calling method, not using parentheses
 
# You need to use parentheses if you want to work with the result immediately.
# e.g., if a method returns an array and we want to reverse element order:
results = method_name(parameter1, parameter2).reverse

Method Definitions[edit]

Methods are defined using the keyword def followed by the method name. Method parameters are specified between parentheses following the method name. The method body is enclosed by this definition on the top and the word end on the bottom. By convention method names that consist of multiple words have each word separated by an underscore.

Example:

def output_something(value)
  puts value 
end

Return Values[edit]

Methods return the value of the last statement executed. The following code returns the value x+y.

def calculate_value(x,y)
  x + y
end

An explicit return statement can also be used to return from function with a value, prior to the end of the function declaration. This is useful when you want to terminate a loop or return from a function as the result of a conditional expression.

Note, if you use "return" within a block, you actually will jump out from the function, probably not what you want. To terminate block, use break. You can pass a value to break which will be returned as the result of the block:

six = (1..10).each {|i| break i if i > 5}

In this case, six will have the value 6.

Default Values[edit]

A default parameter value can be specified during method definition to replace the value of a parameter if it is not passed into the method.

def some_method(value='default', arr=[])
  puts value
  puts arr.length
end
 
some_method('something')

The method call above will output:

  something
  0

The following is a syntax error in Ruby 1.8

  def foo( i = 7, j ) # Syntax error in Ruby 1.8.7 Unexpected ')', expecting '='
    return i + j
  end

The above code will work in 1.9.2 and will be logically equivalent to the snippet below

  def foo( j, i = 7)
    return i + j
  end

Variable Length Argument List, Asterisk Operator[edit]

The last parameter of a method may be preceded by an asterisk(*), which is sometimes called the 'splat' operator. This indicates that more parameters may be passed to the function. Those parameters are collected up and an array is created.

  def calculate_value(x,y,*otherValues)
    puts otherValues
  end
 
  calculate_value(1,2,'a','b','c')

In the example above the output would be ['a', 'b', 'c'].

The asterisk operator may also precede an Array argument in a method call. In this case the Array will be expanded and the values passed in as if they were separated by commas.

  arr = ['a','b','c']
  calculate_value(*arr)

has the same result as:

  calculate_value('a','b','c')

Another technique that Ruby allows is to give a Hash when invoking a function, and that gives you best of all worlds: named parameters, and variable argument length.

  def accepts_hash( var )
    print "got: ", var.inspect # will print out what it received
  end
 
  accepts_hash :arg1 => 'giving arg1', :argN => 'giving argN'
  # => got: {:argN=>"giving argN", :arg1=>"giving arg1"}

You see, the arguments for accepts_hash got rolled up into one hash variable. This technique is heavily used in the Ruby On Rails API.

Also note the missing parenthesis around the arguments for the accepts_hash function call, and notice that there is no { } Hash declaration syntax around the :arg1 => '...' code, either. The above code is equivalent to the more verbose:

  accepts_hash( :arg1 => 'giving arg1', :argN => 'giving argN' )  # argument list enclosed in parens
  accepts_hash( { :arg1 => 'giving arg1', :argN => 'giving argN' } ) # hash is explicitly created

Now, if you are going to pass a code block to function, you need parentheses.

  accepts_hash( :arg1 => 'giving arg1', :argN => 'giving argN' )  { |s| puts s }
  accepts_hash( { :arg1 => 'giving arg1', :argN => 'giving argN' } )  { |s| puts s } 
  # second line is more verbose, hash explicitly created, but essentially the same as above

The Ampersand Operator[edit]

Much like the asterisk, the ampersand(&) may precede the last parameter of a function declaration. This indicates that the function expects a code block to be passed in. A Proc object will be created and assigned to the parameter containing the block passed in.

Also similar to the ampersand operator, a Proc object preceded by an ampersand during a method call will be replaced by the block that it contains. Yield may then be used.

  def method_call
    yield
  end
 
  method_call(&someBlock)

Understanding blocks, Procs and methods[edit]

Introduction[edit]

Ruby provides the programmer with a set of very powerful features borrowed from the domain of functional programming, namely closures, higher-order functions, and first-class functions [1]. These features are implemented in Ruby by means of code blocks, Proc objects, and methods (that are also objects)—concepts that are closely related and yet differ in subtle ways. In fact, I found myself quite confused about this topic, having difficulty understanding the difference between blocks, procs, and methods as well as unsure about the best practices of using them. Additionally, having some background in Lisp and years of Perl experience, I was unsure of how the Ruby concepts map to similar idioms from other programming languages like Lisp’s functions and Perl’s subroutines. Sifting through hundreds of newsgroup posts, I saw that I am not the only one with this problem and, in fact, quite a lot of “Ruby Nubies” struggle with the same ideas.

In this article I lay out my understanding of this facet of Ruby, which comes as a result of extensive research of Ruby books, documentation, and comp.lang.ruby, in sincere hope that other people will find it useful as well.

Procs[edit]

Shamelessly ripping from the Ruby documentation, Procs are defined as follows: Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables.

A useful example is also provided:

  def gen_times(factor)
      return Proc.new {|n| n*factor }
  end
 
  times3 = gen_times(3)      # 'factor' is replaced with 3
  times5 = gen_times(5)
 
  times3.call(12)               #=> 36
  times5.call(5)                #=> 25
  times3.call(times5.call(4))   #=> 60

Procs play the role of functions in Ruby. It is more accurate to call them function objects, since like everything in Ruby they are objects. Such objects have a name in the folklore - functors. A functor is defined as an object to be invoked or called as if it were an ordinary function, usually with the same syntax, which is exactly what a Proc is.

From the example and the definition above, it is obvious that Ruby Procs can also act as closures. On Wikipedia, a closure is defined as a function that refers to free variables in its lexical context. Note how closely it maps to the Ruby definition blocks of code that have been bound to a set of local variables.

More on Procs[edit]

Procs in Ruby are first-class objects, since they can be created during runtime, stored in data structures, passed as arguments to other functions and returned as the value of other functions. Actually, the gen_times example demonstrates all of these criteria, except for “passed as arguments to other functions”. This one can be presented as follows:

  def foo (a, b)
      a.call(b)
  end
 
  putser = Proc.new {|x| puts x}
  foo(putser, 34)

There is also a shorthand notation for creating Procs - the Kernel method lambda [2] (we’ll come to methods shortly, but for now assume that a Kernel method is something akin to a global function, which can be called from anywhere in the code). Using lambda the Proc object creation from the previous example can be rewritten as:

  putser = lambda {|x| puts x}

Actually, there are two slight differences between lambda and Proc.new. First, argument checking. The Ruby documentation for lambda states: Equivalent to Proc.new, except the resulting Proc objects check the number of parameters passed when called. Here is an example to demonstrate this:

  pnew = Proc.new {|x, y| puts x + y}
  lamb = lambda {|x, y| puts x + y}
 
  # works fine, printing 6
  pnew.call(2, 4, 11)
 
  # throws an ArgumentError
  lamb.call(2, 4, 11)

Second, there is a difference in the way returns are handled from the Proc. A return from Proc.new returns from the enclosing method (acting just like a return from a block, more on this later):

  def try_ret_procnew
      ret = Proc.new { return "Baaam" }
      ret.call
      "This is not reached"
  end
 
  # prints "Baaam"
  puts try_ret_procnew

While return from lambda acts more conventionally, returning to its caller:

  def try_ret_lambda
      ret = lambda { return "Baaam" }
      ret.call
      "This is printed"
  end
 
  # prints "This is printed"
  puts try_ret_lambda

With this in light, I would recommend using lambda instead of Proc.new, unless the behavior of the latter is strictly required. In addition to being a whopping two characters shorter, its behavior is less surprising.

Methods[edit]

Simply put, a method is also a block of code. However, unlike Procs, methods are not bound to the local variables around them. Rather, they are bound to some object and have access to its instance variables [3]:

  class Boogy
      def initialize
          @dix = 15
      end
 
      def arbo
          puts "#{@dix} ha\n"
      end
  end
 
  # initializes an instance of Boogy
  b = Boogy.new
 
  # prints "15 ha"
  b.arbo

A useful idiom when thinking about methods is that you are sending messages to the object that the method is defined for. Given a receiver - an object that has some method defined - we send it a message, which contains the name of the method, and optionally provides the arguments that the method would receive. In the example above, calling the method arbo without any arguments, is akin to sending a message with just “arbo” as the argument.

Ruby supports the message sending idiom more directly, by including the send method in class Object (which is the parent of all objects in Ruby). So the following three lines are equivalent to the arbo method call:

  # method is called on the object, with no arguments
  b.arbo
 
  # method/message name is given as a string
  b.send("arbo")
 
  # method/message name is given as a symbol
  b.send(:arbo)

Note that methods can also be defined in the so-called “top-level” scope, which is not inside any user-defined class. For example:

  def say (something)
      puts something
  end
 
  say "Hello"

While it seems that the method say is “free-standing”, it is not - Ruby silently tucks it into the Object class, which represents the scope of your application:

  def say (something)
      puts something
  end
 
  say "Hello"
  Object.send(:say, "Hello") # this will be the same as the above line

But this doesn’t really matter, and for all practical purposes say can be seen as an independent method. Which is, by the way, just what’s called a “function” in some languages (like C and Perl). The following Proc is, in many ways similar:

  say = lambda {|something| puts something}
 
  say.call("Hello")
 
  # same effect
  say["Hello"]

The [] construct is a synonym to call in the context of Proc [4]. Methods, however, are more versatile than procs and support a very important feature of Ruby, which I will present right after explaining what blocks are.

Blocks[edit]

Blocks are so closely related to Procs that it gives many newbies a headache trying to decipher how they actually differ. I will try to ease on comprehension with a (hopefully not too corny) metaphor. Blocks, as I see them, are unborn Procs. Blocks are the larval, Procs are the insects. A block does not live on its own - it prepares the code for when it will actually become alive, and only when it is bound and converted to a Proc, it starts living:

  # a naked block can't live in Ruby
  # this is a compilation error !
  {puts "hello"}
 
  # now it's alive, having been converted
  # to a Proc !
  pr = lambda {puts "hello"}
 
  pr.call

Is that it, is that what all the fuss is about, then ? No, not at all. The designer of Ruby, Matz saw that while passing Procs to methods (and other Procs) is nice and allows high-level functions and all kinds of fancy functional stuff, there is one common case that stands high above all other cases - passing a single block of code to a method that makes something useful out of it, for example iteration. And as a very talented designer, Matz decided that it is worthwhile to emphasize this special case, and make it both simpler and more efficient.

Passing a block to a method[edit]

No doubt that any programmer who has spent at least a couple of hours with Ruby has been shown the following examples of Ruby glory (or something very similar):

  10.times do |i|
      print "#{i} "
  end
 
  numbers = [1, 2, 5, 6, 9, 21]
 
  numbers.each do |x|
      puts "#{x} is " + (x >= 3 ? "many" : "few")
  end
 
  squares = numbers.map {|x| x * x}

(Note that do |x| ... end is equivalent to { |x| ... }.)

Such code is, in my opinion, the part of what makes Ruby the clean, readable, and wonderful language it is. What happens here behind the scenes is quite simple, or at least may be depicted in a very simple way. Perhaps Ruby may not implement it exactly the way I am going to describe it, since there are optimization considerations surely playing their role, but it is definitely close enough to the truth to serve as a metaphor for understanding.

Whenever a block is appended to a method call, Ruby automatically converts it to a Proc object but one without an explicit name. The method, however, has a way to access this Proc, by means of the yield statement. See the following example for clarification:

  def do_twice
      yield 
      yield
  end
 
  do_twice {puts "Hola"}

The method do_twice is defined and called with an attached block. Although the method did not explicitly ask for the block in its arguments list, the yield can call the block. This can be implemented in a more explicit way using a Proc argument:

  def do_twice(what)
      what.call
      what.call
  end
 
  do_twice lambda {puts "Hola"}

This is equivalent to the previous example but using blocks with yield is cleaner and better optimized since only one block is passed to the method. Using the Proc approach, any amount of code blocks can be passed:

  def do_twice(what1, what2, what3)
      2.times do
          what1.call
          what2.call
          what3.call
      end
  end
 
  do_twice(   lambda {print "Hola, "},
              lambda {print "querido "},
              lambda {print "amigo\n"})

This is important to note that many people frown at passing blocks and prefer explicit Procs instead. Their rationale is that a block argument is implicit and one has to look through the whole code of the method to see if there are any calls to yield there, while a Proc is explicit and can be immediately spotted in the argument list. While this is simply a matter of taste, understanding both approaches is vital.

The ampersand (&)[edit]

The ampersand operator can be used to explicitly convert between blocks and Procs in a couple of cases. It is worthy to understand how these work.

Remember how I said that although an attached block is converted to a Proc under the hood, it is not accessible as a Proc from inside the method ? Well, if an ampersand is prepended to the last argument in the argument list of a method, the block attached to this method is converted to a Proc object and gets assigned to that last argument:

  def contrived(a, &f)
      # the block can be accessed through f
      f.call(a)
 
      # but yield also works !
      yield(a)
  end
 
  # this works
  contrived(25) {|x| puts x}
 
  # this raises ArgumentError, because &f 
  # isn't really an argument - it's only there 
  # to convert a block
  contrived(25, lambda {|x| puts x})

Another (IMHO far more efficacious) use of the ampersand is the other-way conversion - converting a Proc into a block. This is very useful because many of Ruby’s great built-ins, and especially the iterators, expect to receive a block as an argument, and sometimes it’s much more convenient to pass them a Proc. The following example is taken right from the excellent “Programming Ruby” book by the pragmatic programmers:

  print "(t)imes or (p)lus: "
  times = gets
  print "number: "
  number = Integer(gets)
  if times =~ /^t/
      calc = lambda {|n| n*number }
  else
      calc = lambda {|n| n+number }
  end
  puts((1..10).collect(&calc).join(", "))

The collect method expects a block, but in this case it is very convenient to provide it with a Proc, since the Proc is constructed using knowledge gained from the user. The ampersand preceding calc makes sure that the Proc object calc is turned into a code block and is passed to collect as an attached block.

The ampersand also allows the implementation of a very common idiom among Ruby programmers: passing method names into iterators. Assume that I want to convert all words in an Array to upper case. I could do it like this:

  words = %w(Jane, aara, multiko)
  upcase_words = words.map {|x| x.upcase}
 
  p upcase_words

This is nice, and it works, but I feel it’s a little bit too verbose. The upcase method itself should be given to map, without the need for a separate block and the apparently superfluous x argument. Fortunately, as we saw before, Ruby supports the idiom of sending messages to objects, and methods can be referred to by their names, which are implemented as Ruby Symbols. For example:

  p "Erik".send(:upcase)

This, quite literally, says send the message/method upcase to the object “Erik”. This feature can be utilized to implement the map {|x| x.upcase} in an elegant manner, and we’re going to use the ampersand for this ! As I said, when the ampersand is prepended to some Proc in a method call, it converts the Proc to a block. But what if we prepend it not to a Proc, but to another object ? Then, Ruby’s implicit type conversion rules kick in, and the to_proc method is called on the object to try and make a Proc out of it. We can use this to implement to_proc for Symbol and achieve what we want:

  class Symbol
 
      # A generalized conversion of a method name
      # to a proc that runs this method.
      #
      def to_proc
          lambda {|x, *args| x.send(self, *args)}
      end
 
  end
 
  # Voilà !
  words = %w(Jane, aara, multiko)
  upcase_words = words.map(&:upcase)

Dynamic methods[edit]

You can define a method on "just one object" in Ruby.

  a = 'b'
  def a.some_method
    'within a singleton method just for a'
  end
  >> a.some_method
  => 'within a singleton method just for a'

Or you can use define_(singleton_)method, which preserves the scope around the definition, as well.

  a = 'b'
  a.define_singleton_method(:some_method) {
    'within a block method'
  }
  a.some_method

Special methods[edit]

Ruby has a number of special methods that are called by the interpreter. For example:

  class Chameleon
    alias __inspect__ inspect
    def method_missing(method, *arg)
      if (method.to_s)[0..2] == "to_"
        @identity = __inspect__.sub("Chameleon", method.to_s.sub('to_','').capitalize)
        def inspect
          @identity
        end
        self
      else
        super #method_missing overrides the default Kernel.method_missing
              #pass on anything we weren't looking for so the Chameleon stays unnoticed and uneaten ;)
      end
    end
  end
  mrlizard = Chameleon.new
  mrlizard.to_rock

This does something silly but method_missing is an important part of meta-programming in Ruby. In Ruby on Rails it is used extensively to create methods dynamically.

Another special methods is initialize that ruby calls whenever a class instance is created, but that belongs in the next chapter: Classes.

Conclusion[edit]

Ruby doesn’t really have functions. Rather, it has two slightly different concepts - methods and Procs (which are, as we have seen, simply what other languages call function objects, or functors). Both are blocks of code - methods are bound to Objects, and Procs are bound to the local variables in scope. Their uses are quite different.

Methods are the cornerstone of object-oriented programming, and since Ruby is a pure-OO language (everything is an object), methods are inherent to the nature of Ruby. Methods are the actions Ruby objects do - the messages they receive, if you prefer the message sending idiom.

Procs make powerful functional programming paradigms possible, turning code into a first-class object of Ruby allowing to implement high-order functions. They are very close kin to Lisp’s lambda forms (there’s little doubt about the origin of Ruby’s Proc constructor lambda)

The construct of a block may at first be confusing, but it turns out to be quite simple. A block is, as my metaphor goes, an unborn Proc - it is a Proc in an intermediate state, not bound to anything yet. I think that the simplest way to think about blocks in Ruby, without losing any comprehension, would be to think that blocks are really a form of Procs, and not a separate concept. The only time when we have to think of blocks as slightly different from Procs is the special case when they are passed as the last argument to a method which may then access them using yield.

That’s about it, I guess. I know for sure that the research I conducted for this article cleared many misunderstandings I had about the concepts presented here. I hope others will learn from it as well. If you see anything you don’t agree with - from glaring errors to small inaccuracies, feel free to amend the book.

Notes[edit]

[1] It seems that in the pure, theoretical interpretation what Ruby has isn’t first-class functions per se. However, as this article demonstrates, Ruby is perfectly capable of fulfilling most of the requirements for first-class functions, namely that functions can be created during the execution of a program, stored in data structures, passed as arguments to other functions, and returned as the values of other functions.

[2] lambda has a synonym - proc, which is considered ‘mildly deprecated’ (mainly because proc and Proc.new are slightly different, which is confusing). In other words, just use lambda.

[3] These are ‘instance methods’. Ruby also supports ‘class methods’, and ‘class variables’, but that is not what this article is about.

[4] Or more accurately, call and [] both refer to the same method of class Proc. Yes, Proc objects themselves have methods !