views:

114

answers:

1

I've been reading the Ruby Programming Language book by Flanagan-Matz

Context: Difference between Proc.new and lambda w.r.t return statements

The book states that a return within a lambda should not raise a LocalJumpError (since lambdas are akin to method calls). A return in a lambda just exits the lambda - not the method enclosing the iterator.

However the following code-snippet says otherwise. What is the catch here?

def caller( aProc, switch)
  puts "Start Caller"
  case switch
    when :normal_block; iterator &aProc
    when :block_parameter; iterator_blockparam(&aProc)
    else iterator_param(aProc)
  end
  puts "End Caller"
end

def iterator
  puts "Begin iterator"
  [1,2,3,4].each { |x| yield x  }
  puts "End iterator"
end
def iterator_blockparam(&block)
  puts "Start Iterator wBlockParam"
  puts "Block is {block.lambda? ? 'Lambda' : 'Proc'}"
  [1,2,3,4].each { |x| block[x]  }
  puts "End Iterator wBlockParam"
end
def iterator_param(aProc)
  puts "Start Iterator wParam"
  puts "Block is {aProc.lambda? ? 'Lambda' : 'Proc'}"
  [1,2,3,4].each{ |x| aProc[x]}
  puts "End Iterator wParam"
end
 # enclosing method Proc.new already returned.
no3proc = Proc.new{|x| return -101 if x == 3; puts x }
no3lambda = lambda{|x| return -101 if x == 3; puts x }

#~ caller( no3proc, :normal_block)         #=> LocalJumpError
caller( no3lambda, :normal_block )       #  => LJE
#~ caller( no3proc, :block_parameter)        #=> LJE
#~ caller( no3lambda, :block_parameter)       # works!
#~ caller(no3proc, :with_param)               #=> LJE
#~ caller(no3lambda, :with_param)              # works!
+2  A: 
Dave Sims
+1 for all the effort :) I spent a Saturday trying to come up with a convincing explanation for this one... before giving up to SO
Gishu
Heh, yeah thanks a lot, now I'm obsessed with it as well :) I'm actually looking at the C code for yield.
Dave Sims