Want to stay on top? Ruby Weekly is a once-weekly e-mail newsletter covering the latest Ruby and Rails news.
     Feed Icon

Closures in Ruby

By Peter Cooper / January 16, 2007

Bruce Tate continues his fine Crossing Borders series with a look at Ruby's support for closures. If code blocks and block techniques used by routines such as Rails' respond_to confuse you, it's a great primer.

Comments

  1. Brendan says:

    Interesting link, but one caution for anyone about to read it:
    The author presents the 'def fun(&b); yield; end' style as being an anonymous function, which it isn't; For instance, a return in the closure will kill it. Instead, for example, 'def fun(&b); (lambda &b).call; end' will allow full closures, complete with returns.

  2. Peter Cooper says:

    That technique is also sometimes used with ERb to support 'return' in ERb templates.

  3. Peter Bex says:

    I think he's missing a major point of closures: the fact that they can refer to variables in the definition's surrounding scope even after the function in which they are defined has returned. In Javascript, this is very natural:


    function make_adder(x) {
    return function(y) { return x + y; };
    }

    var add_ten = make_adder(10);
    alert(add_ten(1)); /* Displays 11 */

    As has been mentioned, this is a little awkward in Ruby:


    def make_adder(x)
    return Proc.new {|y| x + y}
    # Or
    return lambda {|y| x + y }
    # Or
    return lambda {|y| return x + y}
    # But not!
    return Proc.new{|y| return x + y}
    # This gives an error 'unexpected return', because the function
    # this Proc is returning from is not itself, but make_adder, which is not
    # on the stack anymore
    end

    add_ten = make_adder(10)
    puts add_ten.call(1) # Displays 11

    puts add_ten(1) # Gives an error

    The requirement to use the call method makes it not as transparent as it should be, since closures are (or should be) simply functions, like in Javascript (or any Lisp)

  4. Ezra says:

    you can use [] brackets to call a proc as well. so

    puts add_ten.call(1) # Displays 11

    puts add_ten(1) # Gives an error

    puts add_ten[1] # Displays 11

Other Posts to Enjoy

Twitter Mentions