Comment by vidarh
More specifically blocks (and "proc"'s) return from the defining scope. This is just a minor clarification, but it matters, because if you pass a block down from where it is defined, and the block calls "return" it will still not just exit from the method where it was called, but from the method where it was defined.
This can sometimes be useful: A calling method can pass down a block or proc to control if/when it wants an early return.
Basically Ruby has two types of closures:
* A return in a lambda returns to the calling scope. So basically, it returns to after where the "call" method is invoked.
* A return in a block or a proc returns from the scope in which it was defined (this is also why you get LocalJumpError if you try to return a block or a proc, but not a lambda to the method calling the one where the block or proc is defined).
When you name a block, you get a Proc object, same as you get when you take the value of a lambda or proc.
In practice, that blocks in MRI are not Proc objects already is just an implementation detail/optimisation. I have a long-standing hobby project to write a Ruby compiler, and there a "proc" and a bare block are implemented identically in the backend.