Search code examples
rubylambdayieldproc-object

Behavior of 'return' keyword within a ruby block


Can someone explain the behavior of the following

def iterate
  return yield
  return "end of iterate"
end

def test_iterate
  assert_equal( "end of iterate",  iterate { return "end of block" } )
  assert_equal( "end of block",  iterate { "end of block" } )
end

I understand that Procs ( Which is what blocks are ) should return within the scope they are called. ( Unlike lambdas ) With this in mind, shouldn't both calls in the tests return "end of block"?

This test passes on 'ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]' ( OSX 10.6.7 )


Solution

  • The return keyword returns from the lexicaly enclosing method. That is, *test_iterate*.

    To return a certain value from a block in a dynamically scoped fashion, you should use the break keyword instead.

    In your case:

    iterate { break("end of block") }
    

    The test will fail. because the second return statement of the iterate method will never run.

    The intended semantics should be accomplished by using exceptions:

    def iterate
      return yield
      rescue :exception
        return "end of iterate"
    end
    
    def test_iterate
      assert_equal( "end of iterate",  iterate { raise :exception } )
      assert_equal( "end of block",  iterate { "end of block" } )
    end