3

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 )

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338

1 Answers1

4

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
Pedro Rolo
  • 28,273
  • 12
  • 60
  • 94