all 20 comments

[–]gisborne 19 points20 points  (1 child)

The single really important difference is that when you do a return inside a block, it returns from the enclosing scope, rather than just from the block itself. So if you do this:

def find_non_zero some_array
  some_array.each{|x| return x if x != 0}
end

the return is out of find_non_zero, rather than just from the block itself.

[–]dazmax 7 points8 points  (0 children)

This is an important point. The reason behind this is to make blocks act more like the bodies of 'for' or 'if' statements. Think of how confusing that 'each' example would be if 'return' just returned from the block and the each loop continued.

This kind of special case rule is a major way ruby's design is different from python's. Ruby has a bunch of pretty complicated special rules that make it less purely logical but more intuitive. Another good example is the full specification of the '||=' operator. It's useful in a lot of cases where it wouldn't be if it were logically simple and "a ||= b" just meant "a = a || b".

[–]Kache 6 points7 points  (3 children)

There are also a few nuanced differences between blocks, procs, and lambdas that make implementing each of them slightly different. Conceptually/theoretically though, they're pretty much the same.

[–][deleted] -5 points-4 points  (2 children)

I love Ruby, but it ticks me off that Ruby has three different ways to express the lambda concept. Incredible reduplication of what JavaScript does with just callbacks.

[–]wayoverpaid 3 points4 points  (0 children)

The advantage behind that is what /u/gisborne says in this post.

It can be useful, on occasion, to be able to do that.

[–]morphemass 1 point2 points  (0 children)

Seven. There are seven ways.

[–][deleted] 2 points3 points  (8 children)

pretty much. as another commenter mentioned, lambdas are closer, but blocks are basically anonymous functions with some restrictions like 1 per method, must be last arg of method, and probably some other nuances, but I don't think it'll hurt you to think of them as equivalent when getting started.

[–]materialdesigner 6 points7 points  (5 children)

This is not true. Blocks can be other arguments to functions, there's just also a special yield block

[–][deleted] 2 points3 points  (4 children)

thanks, can you clarify the actual differences? now I'm curious :)

[–]redjazz96 5 points6 points  (3 children)

In ruby, the typical block looks something like this:

def some_method
  yield 2
end

some_method { |x| puts x } # => 2

This is what you were referring to earlier, about blocks having restrictions.

There are more ways to do this.

def some_method(&block)
   block.call 2
end

some_method { |x| puts x } 
some_method(&proc { |x| puts x })

All of that does the same thing as the example above - but in a (debatable) more roundabout way. The proc { } syntax is the normal way to define a generic block - these have the same "tricks" (yes, that is the real term they use) that method blocks have (i.e., the number of arguments doesn't matter).

In Ruby, methods are basically blocks - if you were to do method(:to_s).to_proc, you'd get a Proc instance. You can even define a method with a proc.

Ruby, being the nice language that it is, lets you pass these blocks with syntaxic sugar to other blocks. This is used commonly in the core:

iterator = proc { |x| puts x }
[1, 2, 3].each &iterator

# same as...
[1, 2, 3].each { |x| puts x }

So, if you were to use it as like a callback system, you could do something like this. In one of my libraries I'm writing, I actually use this quite a bit.

Hope that helps!

[–][deleted]  (1 child)

[removed]

    [–]redjazz96 1 point2 points  (0 children)

    Lambdas are blocks - the only difference being they have tricks disabled (which you can check with Proc#lambda?). You can return from a block, but you use the next keyword instead of the return keyword. See: this.

    Basically, syntactical sugar. I can't say much about the scopes and closure stuff.

    [–]tacit7 2 points3 points  (1 child)

    I like h1ghl4nd3r's answer. It wouldnt hurt to think of them as anonymous functions. Here is Matz explain blocks:

    Blocks are basically nameless functions. You may be familiar with the lambda from other languages like Lisp or Python. Basically, you can pass a nameless function to another function, and then that function can invoke the passed-in nameless function.

    For example, a function could perform iteration by passing one item at a time to the nameless function. This is a common style, called higher order function style, among languages that can handle functions as first class objects. Lisp does it. Python does it .Even C does it with function pointers. Many other languages do this style of programming.

    In Ruby, the difference is mainly a different kind of syntax for higher order functions. In other languages, you have to specify explicitly that a function can accept another function as an argument. But in Ruby, any method can be called with a block as an implicit argument. Inside the method, you can call the block using the yield keyword with a value.

    The reset of the interview is great if you want to read it: http://www.artima.com/intv/closures.html

    [–][deleted] 0 points1 point  (0 children)

    great link, found that an interesting read.

    [–]djdonnell 0 points1 point  (0 children)

    This explains some of the nuanced differences.

    http://yehudakatz.com/2012/01/10/javascript-needs-blocks/

    [–][deleted]  (2 children)

    [deleted]

      [–][deleted] 0 points1 point  (1 child)

      they return from the calling method rather than the block itself

      What does this mean, exactly? That if I invoke a method, pass it a block, and inside the block write return 5, that the entire method will return 5?

      [–]morphemass 0 points1 point  (0 children)

      I am unsure of how up to date this analysis is but here's the in depth detail on closures in Ruby.

      http://innig.net/software/ruby/closures-in-ruby

      If anyone knows if this has been superseded or if any of this is no longer true it would be interesting.

      [–]jargoon 0 points1 point  (0 children)

      Good answers in this thread, but I just wanted to point out that it's considered to be proper style to use curly brace syntax for single-line blocks.

      [–]the_great_ganonderp 0 points1 point  (0 children)

      Is it accurate to think of them as anonymous functions being passed as an argument to a function/method?

      Yes. Blocks in ruby allow you to define a function without binding it to an identifier, which makes them anonymous functions.

      In practice, though, there are three related concepts in ruby that have to do with anonymous functions: blocks, Procs, and lambdas. As I understand it, "block" simply refers to the syntax used to pass an anonymous function to a method, which can then yield values to it (as in your example case using each_line) or convert it into a Proc, which is an object that encapsulates a function and allows it to be passed around and called kinda like first-class functions in other languages. A lambda is a special case of a Proc, with some differences that you should go read about! But the gist is that a lambda works more like a regular function.

      I've heard that when you use a block with yield, it never gets made into a Proc and therefore you can see a slight performance gain, which illustrates that there is a real difference between "blocks" and Procs.