From: gwtmp01@... Date: 2006-09-13T23:46:45+09:00 Subject: Re: Struggling with Blocks On Sep 12, 2006, at 12:39 PM, Rick DeNatale wrote: > 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"} These two example illustrate the ability to attach a rescue modifier to a method call. The fact that in these example the method calls are sitting by themselves inside a block is irrelevant--the rescue is associated with the call and not with the enclosing block. You can attach a rescue clause to any statement: (3/0) rescue "divide by zero" [1,2,3].map {|x| x/0 } rescue "divide by zero" I think is important to view blocks as part of the syntax of a method call in the same way that the period, parenthesis, and commas are part of the syntax of a method call: receiver.method(arg1, arg2) { #code in a block } So 'rescue', when it is attached to a single method call, is really part of the syntax of the method call and the surrounding context is of no concern. You can even have a rescue right in the middle of actual arguments: a = Array.new( 3/0 ) # raises ZeroDivisionError a = Array.new( (3/0 rescue 100) ) # creates an array with 100 entries Note: I first tried that last example without the extra set of parens and the parser didn't like it: Array.new( 3/0 rescue 100 ). Seems like an interesting corner case on statement/expression parsing. Anyway, my point is that rescue modifiers and their semantics are orthogonal to block syntax (do/end {} ) and its semantics. > lambda do > raise "help!" > rescue > "gotcha" > end > > is not. In this example, the rescue is *not* a modifier of the method call 'raise'. The parser has fully processed the raise and is attempting to parse the next method call. In that case rescue is not valid because do/end blocks do not open a new exception context in the way that a method call or begin/end block do. It might be easier to see what is going on from a parsing standpoint by substituting semicolons for newlines: lambda do raise "help!" rescue "gotcha" # one statement, a call to raise end lambda do raise "help!"; rescue "gotcha" # two statements, second one invalid end The method/statement modifier version of 'rescue' is syntactically different than the version of 'rescue' attached to method definitions or begin/end blocks. This may not have clarified the question regarding *why* do/end blocks don't create a new exception scope but hopefully it clarifies the syntax associated with a rescue modifier clause. Gary Wright