From: Rick DeNatale Date: 2006-09-13T01:39:57+09:00 Subject: Re: Struggling with Blocks On 9/11/06, Rick DeNatale wrote: > > I have to admit that I was struggling a bit when I made the analogy to > an anonymous method. The key is that begin pushes a new stack frame > onto the call stack. > > You are right about the scoping of local variables. Having spent a bit more time perusing the 1.8 source code, my analogy was a little off. What really happens is that the rescue and ensure statements effectively push a tag onto a stack which comprises local variables on the C call stack, and then do a setjmp before executing the code being protected, the tag contains the jmp_buf for setjmp, along with other state needed for exception handling. Raising the exception does a longjmp to the jmp_buf in the tag on the top of the stack, passing a state which indicates that an exception is being raised. The tag stack is also used for other purposes such as implementing break, next, redo, and retry in loops. Now I guess I could say that this "kind of" like an internal call, but it's stretching things a bit further than I'd like The break...end statement really just serves as a syntactic marker to delimit where a series of statements being protected by rescue/else/ensure starts, and where the last rescue/else/ensure ends. If a begin..end sequence doesn't contain any rescue/ensure clauses, it has no effect. def..end also can mark those protected statements, although it also serves the purpose of delimiting a method. Now there might be a reason why the do..end, or {..} of a block can't have the same feature, but I'm scratching my head to figure out why. You CAN have a block which contains a single statement with a rescue modifier: lambda do raise "help!" rescue "gotcha" end is legal as is the semantically equivalent: lambda {raise "help!" rescue "gotcha"} but lambda do raise "help!" rescue "gotcha" end is not. Perhaps someone else (Matz?) can enlighten me/us on why -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/