tags:

views:

228

answers:

7

I am trying to understand blocks and yields and how they work in Ruby. How is a yield used and most of the rails applications use yields in a weird way. Can someone explain to me or show me where to go to understand them.

+1  A: 

In Ruby, methods can check to see if they were called in such a way that a block was provided in addition to the normal arguments. Typically this is done using the block_given? function (you can also include a block in an argument list by affixing an ampersand (&) before the final argument name, this way you will have an explicit reference to the block as a procedure).

If a method is invoked with a block then the method can yield control to the block (call the block) with some arguments, if needed. Consider this example method that demonstrates:

def foo(x)
  puts "OK: called as foo(#{x.inspect})"
  yield("A gift from foo!") if block_given?
end

>> foo(10)
=> OK: called as foo(10)
>> foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
=> OK: called as foo(123)
BLOCK: A gift from foo! How nice =)
maerics
+1  A: 

It's quite possible that someone will provide a truly detailed answer here, but I've always found this post from Robert Sosinski to be a great explanation of the subtleties between blocks, procs & lamdbas.

I should add that I believe the post I'm linking to is specific to ruby 1.8. Some things have changed in ruby 1.9, such as block variables being local to the block. In 1.8, you'd get something like the following:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"

Whereas 1.9 would give you:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"

I don't have 1.9 on this machine so the above might have an error in it.

theIV
Great description in that article, it took me months to figure that all out on my own =)
maerics
I agree. I don't think I knew half of the stuff explained until I read it.
theIV
+1  A: 

I wanted to sort of add why you would do things that way to the already great answers.

No idea what language you are coming from, but assuming it is a static language, this sort of thing will look familiar. This is how you read a file in java

public class FileInput {

  public static void main(String[] args) {

    File file = new File("C:\\MyFile.txt");
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    DataInputStream dis = null;

    try {
      fis = new FileInputStream(file);

      // Here BufferedInputStream is added for fast reading.
      bis = new BufferedInputStream(fis);
      dis = new DataInputStream(bis);

      // dis.available() returns 0 if the file does not have more lines.
      while (dis.available() != 0) {

      // this statement reads the line from the file and print it to
        // the console.
        System.out.println(dis.readLine());
      }

      // dispose all the resources after using them.
      fis.close();
      bis.close();
      dis.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Ignoring the whole stream chaining thing, The idea is this

  1. Initialize resource that needs to be cleaned up
  2. use resource
  3. make sure to clean it up

This is how you do it in ruby

File.open("readfile.rb", "r") do |infile|
    while (line = infile.gets)
        puts "#{counter}: #{line}"
        counter = counter + 1
    end
end

Wildly different. Breaking this one down

  1. tell the File class how to initialize the resource
  2. tell the file class what to do with it
  3. laugh at the java guys who are still typing ;-)

Here, instead of handling step one and two, you basically delegate that off into another class. As you can see, that dramatically brings down the amount of code you have to write, which makes things easier to read, and reduces the chances of things like memory leaks, or file locks not getting cleared.

Now, its not like you can't do something similar in java, in fact, people have been doing it for decades now. It's called the Strategy pattern. The difference is that without blocks, for something simple like the file example, strategy becomes overkill due to the amount of classes and methods you need to write. With blocks, it is such a simple and elegant way of doing it, that it doesn't make any sense NOT to structure your code that way.

This isn't the only way blocks are used, but the others (like the Builder pattern, which you can see in the form_for api in rails) are similar enough that it should be obvious whats going on once you wrap your head around this. When you see blocks, its usually safe to assume that the method call is what you want to do, and the block is describing how you want to do it.

Matt Briggs
+4  A: 

Yes, it is a bit puzzling at first.

In ruby, methods may receive code block that as the name describes are used to perform arbitrarily segments of code.

When a method expects a block, it invokes it by calling the yield function.

This is very handy for instance to iterate a list or to provide a custom algorithm.

Take the following sample

I'm going to define a Person class initialized with a name, and provide a do_with_name method that when invoked, would just pass the name attribute, to the block received.

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name 
        yield( @name ) 
    end
end

This would allow to call that method an pass an arbitrarily code block

For instance to print the name we would do:

person = Person.new("Oscar")

#invoking the method passing a block
person.do_with_name {|string|
    puts "Hey, his name is #{string}"
}

Would print:

Hey, his name is Oscar

Notice, the block receives as parameter a string variable. When the code invokes yield it fills this parameter with the value of @name

yield( @name )

We could provide another block to perform a different action, for instance, reverse the name:

#variable to hold the name reversed
the_name = ""
#invoke the method passing a different block
person.do_with_name { |variable| 
    the_name = variable.reverse
}
puts the_name

Prints racsO

This is exactly the same method, it is just a different block. Notice also the variable name in the block may be different.

This sample is trivial, more interesting usages are for instance to filter all the elements in an array:

 days = ["monday", "tuesday", "wednesday", "thursday", "friday"]  
=> ["monday", "tuesday", "wednesday", "thursday", "friday"]
 # select those which start with 't' 
 days.select { | item |
     item.match /^t/
 }
=> ["tuesday", "thursday"]

Or, we can also provide a custom sort algorithm, for instance based on the string size:

 days.sort { |x,y|
    x.size <=> y.size
 }
=> ["monday", "friday", "tuesday", "thursday", "wednesday"]

I hope this help you to understand it better.

BTW, if the block is optional you should call it like:

yield(value) if block_given?

If is not optional, just invoke it.

OscarRyz
+2  A: 

You might be interested in the answer to Ruby’s yield feature in relation to computer science. Though it's a somewhat different question than yours, it may shed some light on the matter.

Ken Bloom
+3  A: 

This is the best explanation that I can find...

http://railshelper.com/2010/06/12/blocks-and-yield-in-ruby-walkthrough

A: 

I think the best description of Ruby blocks (blocks, Procs, lambdas and methods) can be found here:

HERE HERE :)

Filip
I added that link already.
theIV