views:

265

answers:

2

The following code works fine:

person = {:a=>:A, :b=>:B, :c=>:C}
berson = {:a=>:A1, :b=>:B1, :c=>:C1}

kerson = person.merge(berson) do | key, oldv, newv |
if key == :a
  oldv
elsif key == :b
  newv
else
  key
end
end

puts kerson.inspect

but if I add the return keyword inside the "if block", I get an error:

person = {:a=>:A, :b=>:B, :c=>:C}
berson = {:a=>:A1, :b=>:B1, :c=>:C1}

kerson = person.merge(berson) do | key, oldv, newv |
if key == :a
  return oldv
elsif key == :b
  return newv
else
  return key
end
end

puts kerson.inspect

The error from the above code is:

unexpected return (LocalJumpError)

Can anyone explain this? I thought the 'return' keyword could be optionally used wherever there is already the assumption of a value being returned.

A: 

Nathan's answer may be right, but my understanding of the problem from quick research is subtly different. Although, I'm not guaranteeing this is 100% corrrect.

I think when you do a return inside a block it is actually trying to return from the method that has yielded the block (in this case merge()).

The error is raised because the scope of the response (oldv, newv or key) is no longer valid as you have exited the block to perform the return (remember the return is causing the return from the merge() method).

In summary I think Ruby is exiting the block to try and return from merge() and finding that the return value (oldv, newv or key) is no longer in scope.

Anyway this is what I could work out from my quick research.

Sources: http://blog.jayfields.com/2007/03/ruby-localjumperror-workaround.html http://groups.google.com/group/sketchupruby/browse_thread/thread/17bff6988f12037b

Osseta
Yes, your research has convinced me that my answer is not correct. I'll delete it to avoid confusing anyone.
Nathan Kitchen
No, it is not trying to return from `merge`, it is trying to return from the top level. This has nothing to do with the "scope of the return value" - Chuck's answer is right.
James Baker
+9  A: 

The reason for the error is that blocks don't really have their own scope that they return from — a return from a block is equivalent to returning from the surrounding method. What is the surrounding method here? There is none — it's at the top level, so it's equivalent to doing ruby -e "return", which will give you the same error. If you stick this inside a method, it will make the method return the value of the first branch of the if-clause that gets executed.

Chuck